diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index fd03e1359..90557f365 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -24,6 +24,7 @@ using System.Threading.Tasks; using System.Collections.Immutable; using System.Diagnostics; using Mono.Cecil; +using Cil = Mono.Cecil.Cil; using System.Collections; using System.Threading; @@ -45,7 +46,7 @@ namespace ICSharpCode.Decompiler.IL return new MetadataToken(reader.ReadUInt32()); } - readonly Mono.Cecil.Cil.MethodBody body; + readonly Cil.MethodBody body; readonly CancellationToken cancellationToken; readonly TypeSystem typeSystem; @@ -56,7 +57,7 @@ namespace ICSharpCode.Decompiler.IL BitArray isBranchTarget; List instructionBuilder; - public ILReader(Mono.Cecil.Cil.MethodBody body, CancellationToken cancellationToken) + public ILReader(Cil.MethodBody body, CancellationToken cancellationToken) { if (body == null) throw new ArgumentNullException("body"); @@ -101,7 +102,23 @@ namespace ICSharpCode.Decompiler.IL isBranchTarget = new BitArray(body.CodeSize); stack.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.Empty; + } + } + while (reader.Position < reader.Length) { cancellationToken.ThrowIfCancellationRequested(); int start = reader.Position; diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index eae32fd2d..1c6dc6c50 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -167,12 +167,12 @@ namespace ICSharpCode.Decompiler.IL { this.resultType = resultType; } + StackType resultType; + public override StackType ResultType { get { return resultType; } } protected override InstructionFlags ComputeFlags() { return InstructionFlags.MayPeek; } - StackType resultType; - public override StackType ResultType { get { return resultType; } } public override T AcceptVisitor(ILVisitor visitor) { 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) { } + protected override InstructionFlags ComputeFlags() { return base.ComputeFlags() | InstructionFlags.MayThrow; } - public override T AcceptVisitor(ILVisitor visitor) { 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) { } + protected override InstructionFlags ComputeFlags() { return base.ComputeFlags() | InstructionFlags.MayThrow; } - public override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitRem(this); @@ -366,11 +366,11 @@ namespace ICSharpCode.Decompiler.IL /// Unconditional branch. goto target; public sealed partial class Branch : SimpleInstruction { + public override StackType ResultType { get { return StackType.Void; } } protected override InstructionFlags ComputeFlags() { return InstructionFlags.EndPointUnreachable | InstructionFlags.MayBranch; } - public override StackType ResultType { get { return StackType.Void; } } public override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitBranch(this); @@ -393,11 +393,11 @@ namespace ICSharpCode.Decompiler.IL public DebugBreak() : base(OpCode.DebugBreak) { } + public override StackType ResultType { get { return StackType.Void; } } protected override InstructionFlags ComputeFlags() { return InstructionFlags.SideEffect; } - public override StackType ResultType { get { return StackType.Void; } } public override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitDebugBreak(this); @@ -501,11 +501,11 @@ namespace ICSharpCode.Decompiler.IL public Ckfinite() : base(OpCode.Ckfinite) { } + public override StackType ResultType { get { return StackType.Void; } } protected override InstructionFlags ComputeFlags() { return InstructionFlags.MayPeek | InstructionFlags.MayThrow; } - public override StackType ResultType { get { return StackType.Void; } } public override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitCkfinite(this); @@ -533,6 +533,12 @@ namespace ICSharpCode.Decompiler.IL /// Returns the variable operand. public ILVariable Variable { get { return variable; } } 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(ILVisitor visitor) { return visitor.VisitLdLoc(this); @@ -550,6 +556,12 @@ namespace ICSharpCode.Decompiler.IL readonly ILVariable variable; /// Returns the variable operand. public ILVariable Variable { get { return variable; } } + public override void WriteTo(ITextOutput output) + { + output.Write(OpCode); + output.Write(' '); + variable.WriteTo(output); + } public override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdLoca(this); @@ -567,6 +579,15 @@ namespace ICSharpCode.Decompiler.IL readonly ILVariable variable; /// Returns the variable operand. 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(ILVisitor visitor) { return visitor.VisitStLoc(this); @@ -581,13 +602,13 @@ namespace ICSharpCode.Decompiler.IL this.Value = value; } public readonly string Value; + public override StackType ResultType { get { return StackType.O; } } public override void WriteTo(ITextOutput output) { output.Write(OpCode); output.Write(' '); Disassembler.DisassemblerHelpers.WriteOperand(output, Value); } - public override StackType ResultType { get { return StackType.O; } } public override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdStr(this); @@ -602,13 +623,13 @@ namespace ICSharpCode.Decompiler.IL this.Value = value; } public readonly int Value; + public override StackType ResultType { get { return StackType.I4; } } public override void WriteTo(ITextOutput output) { output.Write(OpCode); output.Write(' '); Disassembler.DisassemblerHelpers.WriteOperand(output, Value); } - public override StackType ResultType { get { return StackType.I4; } } public override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdcI4(this); @@ -623,13 +644,13 @@ namespace ICSharpCode.Decompiler.IL this.Value = value; } public readonly long Value; + public override StackType ResultType { get { return StackType.I8; } } public override void WriteTo(ITextOutput output) { output.Write(OpCode); output.Write(' '); Disassembler.DisassemblerHelpers.WriteOperand(output, Value); } - public override StackType ResultType { get { return StackType.I8; } } public override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdcI8(this); @@ -644,13 +665,13 @@ namespace ICSharpCode.Decompiler.IL this.Value = value; } public readonly double Value; + public override StackType ResultType { get { return StackType.F; } } public override void WriteTo(ITextOutput output) { output.Write(OpCode); output.Write(' '); Disassembler.DisassemblerHelpers.WriteOperand(output, Value); } - public override StackType ResultType { get { return StackType.F; } } public override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdcF(this); @@ -673,11 +694,11 @@ namespace ICSharpCode.Decompiler.IL /// Returns from the current method or lambda. public sealed partial class Return : ILInstruction { + public override StackType ResultType { get { return StackType.Void; } } protected override InstructionFlags ComputeFlags() { return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable; } - public override StackType ResultType { get { return StackType.Void; } } public override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitReturn(this); @@ -717,10 +738,6 @@ namespace ICSharpCode.Decompiler.IL { this.field = field; } - protected override InstructionFlags ComputeFlags() - { - return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow; - } /// Gets/Sets whether the memory access is volatile. public bool IsVolatile { get; set; } /// Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix. @@ -729,6 +746,23 @@ namespace ICSharpCode.Decompiler.IL /// Returns the field operand. public FieldReference Field { get { return field; } } 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(ILVisitor visitor) { return visitor.VisitLdFld(this); @@ -742,14 +776,23 @@ namespace ICSharpCode.Decompiler.IL { this.field = field; } - protected override InstructionFlags ComputeFlags() - { - return base.ComputeFlags() | InstructionFlags.MayThrow; - } readonly FieldReference field; /// Returns the field operand. public FieldReference Field { get { return field; } } 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(ILVisitor visitor) { return visitor.VisitLdFlda(this); @@ -763,10 +806,6 @@ namespace ICSharpCode.Decompiler.IL { this.field = field; } - protected override InstructionFlags ComputeFlags() - { - return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow; - } /// Gets/Sets whether the memory access is volatile. public bool IsVolatile { get; set; } /// Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix. @@ -775,6 +814,25 @@ namespace ICSharpCode.Decompiler.IL readonly FieldReference field; /// Returns the field operand. 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(ILVisitor visitor) { return visitor.VisitStFld(this); @@ -788,10 +846,6 @@ namespace ICSharpCode.Decompiler.IL { this.field = field; } - protected override InstructionFlags ComputeFlags() - { - return InstructionFlags.SideEffect; - } /// Gets/Sets whether the memory access is volatile. public bool IsVolatile { get; set; } /// Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix. @@ -800,6 +854,20 @@ namespace ICSharpCode.Decompiler.IL /// Returns the field operand. public FieldReference Field { get { return field; } } 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(ILVisitor visitor) { return visitor.VisitLdsFld(this); @@ -817,6 +885,12 @@ namespace ICSharpCode.Decompiler.IL readonly FieldReference field; /// Returns the field operand. 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(ILVisitor visitor) { return visitor.VisitLdsFlda(this); @@ -830,10 +904,6 @@ namespace ICSharpCode.Decompiler.IL { this.field = field; } - protected override InstructionFlags ComputeFlags() - { - return base.ComputeFlags() | InstructionFlags.SideEffect; - } /// Gets/Sets whether the memory access is volatile. public bool IsVolatile { get; set; } /// Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix. @@ -842,6 +912,23 @@ namespace ICSharpCode.Decompiler.IL readonly FieldReference field; /// Returns the field operand. 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(ILVisitor visitor) { return visitor.VisitStsFld(this); @@ -859,6 +946,15 @@ namespace ICSharpCode.Decompiler.IL /// Returns the type operand. public TypeReference Type { get { return type; } } 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(ILVisitor visitor) { return visitor.VisitIsInst(this); @@ -872,10 +968,6 @@ namespace ICSharpCode.Decompiler.IL { this.type = type; } - protected override InstructionFlags ComputeFlags() - { - return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow; - } readonly TypeReference type; /// Returns the type operand. public TypeReference Type { get { return type; } } @@ -884,6 +976,23 @@ namespace ICSharpCode.Decompiler.IL /// Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix. public byte UnalignedPrefix { get; set; } 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(ILVisitor visitor) { return visitor.VisitLdObj(this); @@ -897,14 +1006,23 @@ namespace ICSharpCode.Decompiler.IL { this.type = type; } - protected override InstructionFlags ComputeFlags() - { - return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow; - } readonly TypeReference type; /// Returns the type operand. public TypeReference Type { get { return type; } } 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(ILVisitor visitor) { return visitor.VisitUnboxAny(this); @@ -930,11 +1048,11 @@ namespace ICSharpCode.Decompiler.IL public Throw(ILInstruction argument) : base(OpCode.Throw, argument) { } + public override StackType ResultType { get { return StackType.Void; } } protected override InstructionFlags ComputeFlags() { return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable; } - public override StackType ResultType { get { return StackType.Void; } } public override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitThrow(this); @@ -947,11 +1065,11 @@ namespace ICSharpCode.Decompiler.IL public LdLen(ILInstruction argument) : base(OpCode.LdLen, argument) { } + public override StackType ResultType { get { return StackType.I; } } protected override InstructionFlags ComputeFlags() { return base.ComputeFlags() | InstructionFlags.MayThrow; } - public override StackType ResultType { get { return StackType.I; } } public override T AcceptVisitor(ILVisitor visitor) { return visitor.VisitLdLen(this); diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index 1d7f1a077..498b3f425 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/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)#>) {<#=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()")) { #> protected override InstructionFlags ComputeFlags() { 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(ILVisitor visitor) { return visitor.Visit<#=opCode.Name#>(this); @@ -219,7 +223,7 @@ namespace ICSharpCode.Decompiler.IL } <#+ - static string Body(List statements) + static string Body(IEnumerable statements) { StringBuilder b = new StringBuilder(); foreach (var st in statements) { @@ -269,6 +273,22 @@ namespace ICSharpCode.Decompiler.IL public List Flags = new List(); public bool GenerateComputeFlags = true; + + public bool GenerateWriteTo = false; + public List WriteOpCodePrefix = new List(); + public List WriteOpCodeSuffix = new List(); + public List WriteOperand = new List(); + public List WriteArguments = new List(); + + public IEnumerable 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 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) static Action MayBranch = HasFlag("InstructionFlags.MayBranch"); - // HasBranchTarget trait: the instruction has an explicit branch target offset - static Action HasBranchTarget = opCode => {}; - // UnconditionalBranch trait: the instruction does not produce a result normally; it always branches or throws an exception. Implies VoidResult. static Action UnconditionalBranch = VoidResult + HasFlag("InstructionFlags.EndPointUnreachable"); @@ -348,6 +365,9 @@ namespace ICSharpCode.Decompiler.IL opCode.Flags.Add("base.ComputeFlags()"); opCode.ConstructorParameters.Add("ILInstruction 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' @@ -358,6 +378,11 @@ namespace ICSharpCode.Decompiler.IL opCode.ConstructorParameters.Add("ILInstruction right"); opCode.BaseConstructorArguments.Add("left"); 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. @@ -366,12 +391,15 @@ namespace ICSharpCode.Decompiler.IL opCode.BaseClass = "BinaryNumericInstruction"; opCode.ConstructorParameters.Add("OverflowMode overflowMode"); opCode.BaseConstructorArguments.Add("overflowMode"); + opCode.WriteOpCodeSuffix.Add("output.WriteSuffix(overflowMode);"); }; // BinaryNumeric trait: the instruction is derived from BinaryComparisonInstruction. Implies Binary and I4Result. static Action BinaryComparison = opCode => { Binary(opCode); opCode.BaseClass = "BinaryComparisonInstruction"; + opCode.WriteOpCodeSuffix.Add("output.Write('.');"); + opCode.WriteOpCodeSuffix.Add("output.Write(OpType);"); }; // 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.Members.Add("/// Returns the variable operand." + Environment.NewLine + "public ILVariable Variable { get { return variable; } }"); + opCode.GenerateWriteTo = true; + opCode.WriteOperand.Add("output.Write(' ');"); + opCode.WriteOperand.Add("variable.WriteTo(output);"); }; static Action HasFieldOperand = opCode => { @@ -400,6 +431,9 @@ namespace ICSharpCode.Decompiler.IL opCode.ConstructorBody.Add("this.field = field;"); opCode.Members.Add("/// Returns the field operand." + Environment.NewLine + "public FieldReference Field { get { return field; } }"); + opCode.GenerateWriteTo = true; + opCode.WriteOperand.Add("output.Write(' ');"); + opCode.WriteOperand.Add("Disassembler.DisassemblerHelpers.WriteOperand(output, field);"); }; static Action HasTypeOperand = opCode => { @@ -408,6 +442,9 @@ namespace ICSharpCode.Decompiler.IL opCode.ConstructorBody.Add("this.type = type;"); opCode.Members.Add("/// Returns the type operand." + Environment.NewLine + "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. @@ -418,12 +455,9 @@ namespace ICSharpCode.Decompiler.IL opCode.ConstructorParameters.Add(operandType + " value"); opCode.Members.Add("public readonly " + operandType + " Value;"); opCode.ConstructorBody.Add("this.Value = value;"); - opCode.Members.Add("public override void WriteTo(ITextOutput output)" + Environment.NewLine - + "{" + Environment.NewLine - + "\toutput.Write(OpCode);" + Environment.NewLine - + "\toutput.Write(' ');" + Environment.NewLine - + "\tDisassembler.DisassemblerHelpers.WriteOperand(output, Value);" + Environment.NewLine - + "}"); + opCode.GenerateWriteTo = true; + opCode.WriteOperand.Add("output.Write(' ');"); + opCode.WriteOperand.Add("Disassembler.DisassemblerHelpers.WriteOperand(output, Value);"); }; } @@ -431,11 +465,15 @@ namespace ICSharpCode.Decompiler.IL opCode.Interfaces.Add("ISupportsVolatilePrefix"); opCode.Members.Add("/// Gets/Sets whether the memory access is volatile." + Environment.NewLine + "public bool IsVolatile { get; set; }"); + opCode.GenerateWriteTo = true; + opCode.WriteOpCodePrefix.Add("if (IsVolatile)" + Environment.NewLine + "\toutput.Write(\"volatile.\");"); }; static Action SupportsUnalignedPrefix = opCode => { opCode.Interfaces.Add("ISupportsUnalignedPrefix"); opCode.Members.Add("/// Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix." + Environment.NewLine + "public byte UnalignedPrefix { get; set; }"); + opCode.GenerateWriteTo = true; + opCode.WriteOpCodePrefix.Add("if (UnalignedPrefix > 0)" + Environment.NewLine + "\toutput.Write(\"unaligned(\" + UnalignedPrefix + \").\");"); }; #> \ No newline at end of file diff --git a/ICSharpCode.Decompiler/IL/Instructions/BinaryComparisonInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/BinaryComparisonInstruction.cs index 36eedc24b..10afad6bd 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/BinaryComparisonInstruction.cs +++ b/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) { - // 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 { get { return StackType.I4; diff --git a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs index cabeb794a..e4541079f 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs @@ -98,6 +98,9 @@ namespace ICSharpCode.Decompiler.IL /// public Interval ILRange; + /// + /// Writes the ILAst to the text output. + /// public abstract void WriteTo(ITextOutput output); public override string ToString() @@ -107,6 +110,9 @@ namespace ICSharpCode.Decompiler.IL return output.ToString(); } + /// + /// Calls the Visit*-method on the visitor corresponding to the concrete type of this instruction. + /// public abstract T AcceptVisitor(ILVisitor visitor); /// @@ -131,42 +137,5 @@ namespace ICSharpCode.Decompiler.IL /// The instruction stack. /// Receives 'true' if all open 'pop' or 'peek' placeholders were inlined into; false otherwise. internal abstract ILInstruction Inline(InstructionFlags flagsBefore, Stack instructionStack, out bool finished); - - /* - /// - /// 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. - /// - public abstract bool IsPeeking { get; } - - /// - /// 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. - /// - public virtual bool NoResult - { - get { return false; } - } - - /// - /// 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. - /// - 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 transformFunc); - */ } }