diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index f3a69c0c4..7ca69ac4c 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -12,41 +12,46 @@ namespace ICSharpCode.Decompiler.CSharp /// /// Translates from ILAst to C# expressions. /// - class ExpressionBuilder(ICompilation compilation) + class ExpressionBuilder(ICompilation compilation) : ILVisitor { - struct ConvertedExpression(Expression expression, IType type) { + private readonly ICompilation compilation = compilation; + + internal struct ConvertedExpression(Expression expression, IType type) { public readonly Expression Expression = expression; public readonly IType Type = type; } public Expression Convert(ILInstruction inst) { - var expr = TransformExpression(inst).Expression; + var expr = inst.AcceptVisitor(this).Expression; expr.AddAnnotation(inst); return expr; } ConvertedExpression ConvertArgument(ILInstruction inst) { - var cexpr = TransformExpression(inst); + var cexpr = inst.AcceptVisitor(this); cexpr.Expression.AddAnnotation(inst); return cexpr; } - ConvertedExpression TransformExpression(ILInstruction inst) + protected internal override ConvertedExpression VisitLdcI4(LdcI4 inst) + { + return new ConvertedExpression( + new PrimitiveExpression(inst.Value), + compilation.FindType(KnownTypeCode.Int32)); + } + + protected internal override ConvertedExpression VisitLogicNot(LogicNot inst) { - switch (inst.OpCode) { - case OpCode.LdcI4: - return new ConvertedExpression( - new PrimitiveExpression(((ConstantI4)inst).Value), - compilation.FindType(KnownTypeCode.Int32)); - case OpCode.LogicNot: - return new ConvertedExpression( - new UnaryOperatorExpression(UnaryOperatorType.Not, ConvertCondition(((LogicNotInstruction)inst).Operand)), + return new ConvertedExpression( + new UnaryOperatorExpression(UnaryOperatorType.Not, ConvertCondition(inst.Argument)), compilation.FindType(KnownTypeCode.Boolean)); - default: - return ErrorExpression("OpCode not supported: " + inst.OpCode); - } + } + + protected override ConvertedExpression Default(ILInstruction inst) + { + return ErrorExpression("OpCode not supported: " + inst.OpCode); } static ConvertedExpression ErrorExpression(string message) diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index 70e0682cd..a48e3ac7a 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -9,37 +9,34 @@ using System.Threading.Tasks; namespace ICSharpCode.Decompiler.CSharp { - class StatementBuilder(ICompilation compilation) + class StatementBuilder(ICompilation compilation) : ILVisitor { readonly ExpressionBuilder exprBuilder = new ExpressionBuilder(compilation); public Statement Convert(ILInstruction inst) { - switch (inst.OpCode) { - case OpCode.BlockContainer: - return ConvertBlockContainer((BlockContainer)inst); - case OpCode.Ret: - if (inst is ReturnVoidInstruction) - return new ReturnStatement().WithAnnotation(inst); - return new ReturnStatement(ConvertUnaryArg(inst)).WithAnnotation(inst); - case OpCode.Throw: - return new ThrowStatement(ConvertUnaryArg(inst)).WithAnnotation(inst); - case OpCode.ConditionalBranch: - return ConvertConditionalBranch((ConditionalBranch)inst); - default: - return new ExpressionStatement(exprBuilder.Convert(inst)); - } + return inst.AcceptVisitor(this); + } + + protected override Statement Default(ILInstruction inst) + { + return new ExpressionStatement(exprBuilder.Convert(inst)); } - private Statement ConvertConditionalBranch(ConditionalBranch inst) + protected internal override Statement VisitConditionalBranch(ConditionalBranch inst) { var condition = exprBuilder.ConvertCondition(inst.Condition); return new IfElseStatement(condition, new GotoStatement(inst.TargetLabel)); } - private Expression ConvertUnaryArg(ILInstruction inst) + protected internal override Statement VisitBranch(Branch inst) + { + return new GotoStatement(inst.TargetLabel); + } + + protected internal override Statement VisitBlockContainer(BlockContainer inst) { - return exprBuilder.Convert(((UnaryInstruction)inst).Operand); + return ConvertBlockContainer(inst); } public BlockStatement ConvertBlockContainer(BlockContainer container) diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index ed6f50d1a..c1c3b717d 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -67,6 +67,17 @@ + + True + True + Instructions.tt + + + + + + + @@ -85,8 +96,6 @@ - - @@ -101,6 +110,10 @@ TextTemplatingFileGenerator ILOpCodes.cs + + TextTemplatingFileGenerator + Instructions.cs + diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index 2b1a66efc..36de0fc3f 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -13,6 +13,9 @@ namespace ICSharpCode.Decompiler.IL { public class ILReader(Mono.Cecil.Cil.MethodBody body, CancellationToken cancellationToken) { + private readonly Mono.Cecil.Cil.MethodBody body = body; + private readonly CancellationToken cancellationToken = cancellationToken; + internal static ILOpCode ReadOpCode(ref BlobReader reader) { byte b = reader.ReadByte(); @@ -222,7 +225,7 @@ namespace ICSharpCode.Decompiler.IL case ILOpCode.Clt_Un: return Comparison(OpCode.Clt_Un, OpCode.Clt_Un); case ILOpCode.Ckfinite: - return new Ckfinite(); + return new CkFinite(); case ILOpCode.Conv_I1: return Conv(PrimitiveType.I1, OverflowMode.None); case ILOpCode.Conv_I2: @@ -341,7 +344,7 @@ namespace ICSharpCode.Decompiler.IL return LdcI4(reader.ReadSByte()); case ILOpCode.Ldnull: stack.Push(StackType.O); - return new ConstantNull(); + return new LdNull(); case ILOpCode.Ldstr: return DecodeLdstr(); case ILOpCode.Ldftn: @@ -407,7 +410,7 @@ namespace ICSharpCode.Decompiler.IL return BinaryNumeric(OpCode.BitOr); case ILOpCode.Pop: stack.PopOrDefault(); - return new VoidInstruction(); + return new Void(); case ILOpCode.Rem: return BinaryNumeric(OpCode.Rem, OverflowMode.None); case ILOpCode.Rem_Un: diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs new file mode 100644 index 000000000..d4d4cc7c1 --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -0,0 +1,869 @@ +using System; +using Mono.Cecil; + +namespace ICSharpCode.Decompiler.IL +{ + /// + /// Enum representing the type of an . + /// + public enum OpCode + { + /// No operation. Takes 0 arguments and returns void. + Nop, + /// Pops the top of the evaluation stack and returns the value. + Pop, + /// Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'. + Peek, + /// Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack. + Void, + /// A container of IL blocks. + BlockContainer, + /// A block of IL instructions. + Block, + /// Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4). + LogicNot, + /// Adds two numbers. + Add, + /// Subtracts two numbers + Sub, + /// Multiplies two numbers + Mul, + /// Divides two numbers + Div, + /// Division remainder + Rem, + /// Unary negation + Neg, + /// Bitwise AND + BitAnd, + /// Bitwise OR + BitOr, + /// Bitwise XOR + BitXor, + /// Bitwise NOT + BitNot, + /// Retrieves the RuntimeArgumentHandle. + Arglist, + /// if (condition) goto target;. + ConditionalBranch, + /// goto target;. + Branch, + /// Breakpoint instruction + DebugBreak, + /// Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise. + Ceq, + /// Compare greater than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers. + Cgt, + /// Compare greater than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers. + Cgt_Un, + /// Compare less than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers. + Clt, + /// Compare less than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers. + Clt_Un, + /// Non-virtual method call. + Call, + /// Virtual method call. + CallVirt, + /// Checks that the float on top of the stack is not NaN or infinite. + CkFinite, + /// Numeric cast. + Conv, + /// Loads the value of a local variable. (ldarg/ldloc) + Ldloc, + /// Loads the address of a local variable. (ldarga/ldloca) + Ldloca, + /// Stores a value into a local variable. (starg/stloc) + Stloc, + /// Loads a constant string. + LdStr, + /// Loads a constant 32-bit integer. + LdcI4, + /// Loads a constant 64-bit integer. + LdcI8, + /// Loads a constant floating-point number. + LdcF, + /// Loads the null reference. + LdNull, + /// Returns from the current method or lambda. + Return, + /// Shift left + Shl, + /// Shift right + Shr, + /// Load instance field + Ldfld, + /// Load address of instance field + Ldflda, + /// Store value to instance field + Stfld, + /// Load static field + Ldsfld, + /// Load static field address + Ldsflda, + /// Store value to static field + Stsfld, + /// Test if object is instance of class or interface. + IsInst, + /// Indirect load (ref/pointer dereference). + LdInd, + /// Unbox a value. + UnboxAny, + /// Creates an object instance and calls the constructor. + NewObj, + /// Throws an exception. + Throw, + /// Returns the length of an array as 'native unsigned int'. + LdLen, + } + + /// No operation. Takes 0 arguments and returns void. + public sealed partial class Nop() : SimpleInstruction(OpCode.Nop) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitNop(this); + } + } + + /// Pops the top of the evaluation stack and returns the value. + public sealed partial class Pop() : SimpleInstruction(OpCode.Pop) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitPop(this); + } + } + + /// Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'. + public sealed partial class Peek() : SimpleInstruction(OpCode.Peek) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitPeek(this); + } + } + + /// Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack. + public sealed partial class Void() : UnaryInstruction(OpCode.Void) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitVoid(this); + } + } + + /// A container of IL blocks. + public sealed partial class BlockContainer() : ILInstruction(OpCode.BlockContainer) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitBlockContainer(this); + } + } + + /// A block of IL instructions. + public sealed partial class Block() : ILInstruction(OpCode.Block) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitBlock(this); + } + } + + /// Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4). + public sealed partial class LogicNot() : UnaryInstruction(OpCode.LogicNot) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLogicNot(this); + } + } + + /// Adds two numbers. + public sealed partial class Add(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Add, opType, overflowMode) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitAdd(this); + } + } + + /// Subtracts two numbers + public sealed partial class Sub(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Sub, opType, overflowMode) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitSub(this); + } + } + + /// Multiplies two numbers + public sealed partial class Mul(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Mul, opType, overflowMode) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitMul(this); + } + } + + /// Divides two numbers + public sealed partial class Div(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Div, opType, overflowMode) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitDiv(this); + } + } + + /// Division remainder + public sealed partial class Rem(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Rem, opType, overflowMode) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitRem(this); + } + } + + /// Unary negation + public sealed partial class Neg() : UnaryInstruction(OpCode.Neg) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitNeg(this); + } + } + + /// Bitwise AND + public sealed partial class BitAnd(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.BitAnd, opType, overflowMode) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitBitAnd(this); + } + } + + /// Bitwise OR + public sealed partial class BitOr(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.BitOr, opType, overflowMode) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitBitOr(this); + } + } + + /// Bitwise XOR + public sealed partial class BitXor(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.BitXor, opType, overflowMode) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitBitXor(this); + } + } + + /// Bitwise NOT + public sealed partial class BitNot() : UnaryInstruction(OpCode.BitNot) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitBitNot(this); + } + } + + /// Retrieves the RuntimeArgumentHandle. + public sealed partial class Arglist() : SimpleInstruction(OpCode.Arglist) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitArglist(this); + } + } + + /// if (condition) goto target;. + public sealed partial class ConditionalBranch() : UnaryInstruction(OpCode.ConditionalBranch) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitConditionalBranch(this); + } + } + + /// goto target;. + public sealed partial class Branch() : SimpleInstruction(OpCode.Branch) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitBranch(this); + } + } + + /// Breakpoint instruction + public sealed partial class DebugBreak() : SimpleInstruction(OpCode.DebugBreak) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitDebugBreak(this); + } + } + + /// Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise. + public sealed partial class Ceq(StackType opType) : BinaryComparisonInstruction(OpCode.Ceq, opType) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitCeq(this); + } + } + + /// Compare greater than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers. + public sealed partial class Cgt(StackType opType) : BinaryComparisonInstruction(OpCode.Cgt, opType) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitCgt(this); + } + } + + /// Compare greater than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers. + public sealed partial class Cgt_Un(StackType opType) : BinaryComparisonInstruction(OpCode.Cgt_Un, opType) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitCgt_Un(this); + } + } + + /// Compare less than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers. + public sealed partial class Clt(StackType opType) : BinaryComparisonInstruction(OpCode.Clt, opType) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitClt(this); + } + } + + /// Compare less than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers. + public sealed partial class Clt_Un(StackType opType) : BinaryComparisonInstruction(OpCode.Clt_Un, opType) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitClt_Un(this); + } + } + + /// Non-virtual method call. + public sealed partial class Call(MethodReference method) : CallInstruction(OpCode.Call, method) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitCall(this); + } + } + + /// Virtual method call. + public sealed partial class CallVirt(MethodReference method) : CallInstruction(OpCode.CallVirt, method) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitCallVirt(this); + } + } + + /// Checks that the float on top of the stack is not NaN or infinite. + public sealed partial class CkFinite() : SimpleInstruction(OpCode.CkFinite) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitCkFinite(this); + } + } + + /// Numeric cast. + public sealed partial class Conv() : UnaryInstruction(OpCode.Conv) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitConv(this); + } + } + + /// Loads the value of a local variable. (ldarg/ldloc) + public sealed partial class Ldloc() : SimpleInstruction(OpCode.Ldloc) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdloc(this); + } + } + + /// Loads the address of a local variable. (ldarga/ldloca) + public sealed partial class Ldloca() : SimpleInstruction(OpCode.Ldloca) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdloca(this); + } + } + + /// Stores a value into a local variable. (starg/stloc) + public sealed partial class Stloc() : UnaryInstruction(OpCode.Stloc) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitStloc(this); + } + } + + /// Loads a constant string. + public sealed partial class LdStr() : SimpleInstruction(OpCode.LdStr) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdStr(this); + } + } + + /// Loads a constant 32-bit integer. + public sealed partial class LdcI4() : SimpleInstruction(OpCode.LdcI4) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdcI4(this); + } + } + + /// Loads a constant 64-bit integer. + public sealed partial class LdcI8() : SimpleInstruction(OpCode.LdcI8) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdcI8(this); + } + } + + /// Loads a constant floating-point number. + public sealed partial class LdcF() : SimpleInstruction(OpCode.LdcF) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdcF(this); + } + } + + /// Loads the null reference. + public sealed partial class LdNull() : SimpleInstruction(OpCode.LdNull) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdNull(this); + } + } + + /// Returns from the current method or lambda. + public sealed partial class Return() : ILInstruction(OpCode.Return) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitReturn(this); + } + } + + /// Shift left + public sealed partial class Shl(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Shl, opType, overflowMode) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitShl(this); + } + } + + /// Shift right + public sealed partial class Shr(StackType opType, OverflowMode overflowMode) : BinaryNumericInstruction(OpCode.Shr, opType, overflowMode) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitShr(this); + } + } + + /// Load instance field + public sealed partial class Ldfld() : UnaryInstruction(OpCode.Ldfld) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdfld(this); + } + } + + /// Load address of instance field + public sealed partial class Ldflda() : UnaryInstruction(OpCode.Ldflda) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdflda(this); + } + } + + /// Store value to instance field + public sealed partial class Stfld() : BinaryInstruction(OpCode.Stfld) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitStfld(this); + } + } + + /// Load static field + public sealed partial class Ldsfld() : SimpleInstruction(OpCode.Ldsfld) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdsfld(this); + } + } + + /// Load static field address + public sealed partial class Ldsflda() : SimpleInstruction(OpCode.Ldsflda) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdsflda(this); + } + } + + /// Store value to static field + public sealed partial class Stsfld() : UnaryInstruction(OpCode.Stsfld) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitStsfld(this); + } + } + + /// Test if object is instance of class or interface. + public sealed partial class IsInst() : UnaryInstruction(OpCode.IsInst) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitIsInst(this); + } + } + + /// Indirect load (ref/pointer dereference). + public sealed partial class LdInd() : UnaryInstruction(OpCode.LdInd) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdInd(this); + } + } + + /// Unbox a value. + public sealed partial class UnboxAny() : UnaryInstruction(OpCode.UnboxAny) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitUnboxAny(this); + } + } + + /// Creates an object instance and calls the constructor. + public sealed partial class NewObj(MethodReference method) : CallInstruction(OpCode.NewObj, method) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitNewObj(this); + } + } + + /// Throws an exception. + public sealed partial class Throw() : UnaryInstruction(OpCode.Throw) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitThrow(this); + } + } + + /// Returns the length of an array as 'native unsigned int'. + public sealed partial class LdLen() : UnaryInstruction(OpCode.LdLen) + { + + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitLdLen(this); + } + } + + + + public abstract class ILVisitor + { + protected abstract TReturn Default(ILInstruction inst); + + protected internal virtual TReturn VisitNop(Nop inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitPop(Pop inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitPeek(Peek inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitVoid(Void inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitBlockContainer(BlockContainer inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitBlock(Block inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLogicNot(LogicNot inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitAdd(Add inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitSub(Sub inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitMul(Mul inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitDiv(Div inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitRem(Rem inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitNeg(Neg inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitBitAnd(BitAnd inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitBitOr(BitOr inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitBitXor(BitXor inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitBitNot(BitNot inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitArglist(Arglist inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitConditionalBranch(ConditionalBranch inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitBranch(Branch inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitDebugBreak(DebugBreak inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitCeq(Ceq inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitCgt(Cgt inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitCgt_Un(Cgt_Un inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitClt(Clt inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitClt_Un(Clt_Un inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitCall(Call inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitCallVirt(CallVirt inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitCkFinite(CkFinite inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitConv(Conv inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLdloc(Ldloc inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLdloca(Ldloca inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitStloc(Stloc inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLdStr(LdStr inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLdcI4(LdcI4 inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLdcI8(LdcI8 inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLdcF(LdcF inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLdNull(LdNull inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitReturn(Return inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitShl(Shl inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitShr(Shr inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLdfld(Ldfld inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLdflda(Ldflda inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitStfld(Stfld inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLdsfld(Ldsfld inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLdsflda(Ldsflda inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitStsfld(Stsfld inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitIsInst(IsInst inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLdInd(LdInd inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitUnboxAny(UnboxAny inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitNewObj(NewObj inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitThrow(Throw inst) + { + return Default(inst); + } + protected internal virtual TReturn VisitLdLen(LdLen inst) + { + return Default(inst); + } + } +} + diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt new file mode 100644 index 000000000..e8554e9dd --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -0,0 +1,212 @@ +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + OpCode[] opCodes = { + new OpCode("Nop", "No operation. Takes 0 arguments and returns void.", VoidResult, NoArguments), + new OpCode("Pop", "Pops the top of the evaluation stack and returns the value.", NoArguments, NonVoidResult), + new OpCode("Peek", "Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'.", Peeking, NoArguments, NonVoidResult), + new OpCode("Void", "Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.", VoidResult, Unary), + new OpCode("BlockContainer", "A container of IL blocks.", VoidResult), + new OpCode("Block", "A block of IL instructions."), + new OpCode("LogicNot", "Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).", I4Result, Unary), + new OpCode("Add", "Adds two numbers.", BinaryNumeric), + new OpCode("Sub", "Subtracts two numbers", BinaryNumeric), + new OpCode("Mul", "Multiplies two numbers", BinaryNumeric), + new OpCode("Div", "Divides two numbers", BinaryNumeric, MayThrow), + new OpCode("Rem", "Division remainder", BinaryNumeric, MayThrow), + new OpCode("Neg", "Unary negation", Unary, NonVoidResult), + new OpCode("BitAnd", "Bitwise AND", BinaryNumeric), + new OpCode("BitOr", "Bitwise OR", BinaryNumeric), + new OpCode("BitXor", "Bitwise XOR", BinaryNumeric), + new OpCode("BitNot", "Bitwise NOT", Unary, NonVoidResult), + new OpCode("Arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, NonVoidResult), + new OpCode("ConditionalBranch", "if (condition) goto target;.", Unary, MayBranch, HasBranchTarget, VoidResult), + new OpCode("Branch", "goto target;.", NoArguments, UnconditionalBranch, MayBranch, HasBranchTarget), + new OpCode("DebugBreak", "Breakpoint instruction", NoArguments, VoidResult, SideEffect), + new OpCode("Ceq", "Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.", BinaryComparison), + new OpCode("Cgt", "Compare greater than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.", BinaryComparison), + new OpCode("Cgt_Un", "Compare greater than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.", BinaryComparison), + new OpCode("Clt", "Compare less than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.", BinaryComparison), + new OpCode("Clt_Un", "Compare less than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.", BinaryComparison), + new OpCode("Call", "Non-virtual method call.", Call), + new OpCode("CallVirt", "Virtual method call.", Call), + new OpCode("CkFinite", "Checks that the float on top of the stack is not NaN or infinite.", Peeking, NoArguments, MayThrow, VoidResult), + new OpCode("Conv", "Numeric cast.", Unary, NonVoidResult), + new OpCode("Ldloc", "Loads the value of a local variable. (ldarg/ldloc)", NoArguments, NonVoidResult, HasVariableOperand), + new OpCode("Ldloca", "Loads the address of a local variable. (ldarga/ldloca)", NoArguments, RefResult, HasVariableOperand), + new OpCode("Stloc", "Stores a value into a local variable. (starg/stloc)", Unary, VoidResult, HasVariableOperand), + new OpCode("LdStr", "Loads a constant string.", LoadConstant), + new OpCode("LdcI4", "Loads a constant 32-bit integer.", LoadConstant, I4Result), + new OpCode("LdcI8", "Loads a constant 64-bit integer.", LoadConstant, NonVoidResult), + new OpCode("LdcF", "Loads a constant floating-point number.", LoadConstant), + new OpCode("LdNull", "Loads the null reference.", LoadConstant), + new OpCode("Return", "Returns from the current method or lambda.", MayBranch, UnconditionalBranch), + new OpCode("Shl", "Shift left", BinaryNumeric), + new OpCode("Shr", "Shift right", BinaryNumeric), + + new OpCode("Ldfld", "Load instance field", Unary, MayThrow, SideEffect, NonVoidResult, HasFieldOperand), + new OpCode("Ldflda", "Load address of instance field", Unary, MayThrow, RefResult, HasFieldOperand), + new OpCode("Stfld", "Store value to instance field", Binary, SideEffect, MayThrow, VoidResult, HasFieldOperand), + new OpCode("Ldsfld", "Load static field", NoArguments, SideEffect, NonVoidResult, HasFieldOperand), + new OpCode("Ldsflda", "Load static field address", NoArguments, RefResult, HasFieldOperand), + new OpCode("Stsfld", "Store value to static field", Unary, SideEffect, VoidResult, HasFieldOperand), + + new OpCode("IsInst", "Test if object is instance of class or interface.", Unary, NonVoidResult, HasTypeOperand), + new OpCode("LdInd", "Indirect load (ref/pointer dereference).", Unary, NonVoidResult, HasTypeOperand, SideEffect, MayThrow), + new OpCode("UnboxAny", "Unbox a value.", Unary, NonVoidResult, HasTypeOperand, SideEffect, MayThrow), + new OpCode("NewObj", "Creates an object instance and calls the constructor.", Call), + new OpCode("Throw", "Throws an exception.", Unary, MayThrow, UnconditionalBranch), + new OpCode("LdLen", "Returns the length of an array as 'native unsigned int'.", Unary, MayThrow, NonVoidResult), + + + }; +#> +using System; +using Mono.Cecil; + +namespace ICSharpCode.Decompiler.IL +{ + /// + /// Enum representing the type of an . + /// + public enum OpCode + { +<# foreach (OpCode opCode in opCodes) { #> + /// <#=opCode.Description#> + <#=opCode.Name#>, +<# } #> + } + +<# foreach (OpCode opCode in opCodes) { #> + /// <#=opCode.Description#> + public sealed partial class <#=opCode.Name#>(<#=string.Join(", ", opCode.ConstructorParameters)#>) : <#=opCode.BaseClass#>(<#=string.Join(", ", opCode.BaseConstructorArguments)#>) + { +<#=string.Join(Environment.NewLine, opCode.Members)#> + public override TReturn AcceptVisitor(ILVisitor visitor) + { + return visitor.Visit<#=opCode.Name#>(this); + } + } + +<# } #> + + + public abstract class ILVisitor + { + protected abstract TReturn Default(ILInstruction inst); + +<# foreach (OpCode opCode in opCodes) { #> + protected internal virtual TReturn Visit<#=opCode.Name#>(<#=opCode.Name#> inst) + { + return Default(inst); + } +<# } #> + } +} + +<#+ + class OpCode { + public readonly string Name; + public readonly string Description; + + public OpCode(string name, string description, params Action[] traits) + { + this.Name = name; + this.Description = description; + this.BaseConstructorArguments.Add("OpCode." + name); + foreach (var trait in traits) + trait(this); + } + + public List ConstructorParameters = new List(); + + public string BaseClass = "ILInstruction"; + public List BaseConstructorArguments = new List(); + public List Members = new List(); + } + + // Peeking trait: the instruction looks at the top-of-stack without popping + static Action Peeking = opCode => { }; + + // VoidResult trait: the instruction has no result and is not usable as an argument + static Action VoidResult = opCode => { }; + + // NonVoidResult trait: the instruction has a result and is usable as an argument + static Action NonVoidResult = opCode => { }; + + // I4Result trait: the instruction results in StackType.I4. Implies NonVoidResult. + static Action I4Result = NonVoidResult; + + // RefResult trait: the instruction results in StackType.Ref. Implies NonVoidResult. + static Action RefResult = NonVoidResult; + + // MayThrow trait: the instruction may throw exceptions + static Action MayThrow = opCode => {}; + + // MayBranch trait: the instruction may cause control flow to branch (e.g. branch, conditionalbranch, return) + static Action MayBranch = opCode => {}; + + // 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 = opCode => {}; + + // NoArguments trait: the instruction no arguments + static Action NoArguments = opCode => { + opCode.BaseClass = "SimpleInstruction"; + }; + + // Unary trait: the instruction has a single argument + static Action Unary = opCode => { + opCode.BaseClass = "UnaryInstruction"; + }; + + // Binary trait: the instruction has two arguments named 'Left' and 'Right' + static Action Binary = opCode => { + opCode.BaseClass = "BinaryInstruction"; + }; + + // BinaryNumeric trait: the instruction is derived from BinaryNumericInstruction. Implies Binary and NonVoidResult; and implies MayThrow if the overflow mode is checked. + static Action BinaryNumeric = opCode => { + opCode.BaseClass = "BinaryNumericInstruction"; + opCode.ConstructorParameters.Add("StackType opType"); + opCode.ConstructorParameters.Add("OverflowMode overflowMode"); + opCode.BaseConstructorArguments.Add("opType"); + opCode.BaseConstructorArguments.Add("overflowMode"); + }; + + // BinaryNumeric trait: the instruction is derived from BinaryComparisonInstruction. Implies Binary and I4Result. + static Action BinaryComparison = opCode => { + opCode.BaseClass = "BinaryComparisonInstruction"; + opCode.ConstructorParameters.Add("StackType opType"); + opCode.BaseConstructorArguments.Add("opType"); + }; + + // SideEffect trait: the instruction has a non-local side effect + static Action SideEffect = opCode => {}; + + // Call trait: the instruction performs a method call + static Action Call = opCode => { + opCode.BaseClass = "CallInstruction"; + opCode.ConstructorParameters.Add("MethodReference method"); + opCode.BaseConstructorArguments.Add("method"); + }; + + // HasVariableOperand trait: the instruction refers to a local variable + static Action HasVariableOperand = opCode => {}; + + static Action HasFieldOperand = opCode => {}; + + static Action HasTypeOperand = opCode => {}; + + // LoadConstant trait: the instruction loads a compile-time constant. Implies NoArguments and NonVoidResult + static Action LoadConstant = opCode => { + NoArguments(opCode); + NonVoidResult(opCode); + }; +#> \ No newline at end of file diff --git a/ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs index 16da6fbc3..4c95801ee 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs @@ -6,11 +6,12 @@ using System.Threading.Tasks; namespace ICSharpCode.Decompiler.IL { - abstract class BinaryInstruction(OpCode opCode) : ILInstruction(opCode) + public abstract class BinaryInstruction(OpCode opCode) : ILInstruction(opCode) { public ILInstruction Left = Pop; public ILInstruction Right = Pop; + /* public override bool IsPeeking { get { return Left.IsPeeking; } } public override void TransformChildren(Func transformFunc) @@ -26,10 +27,10 @@ namespace ICSharpCode.Decompiler.IL if (finished) Left = Left.Inline(flagsBefore, instructionStack, out finished); return this; - } + }*/ } - class BinaryNumericInstruction(OpCode opCode, StackType opType, OverflowMode overflowMode) + public abstract class BinaryNumericInstruction(OpCode opCode, StackType opType, OverflowMode overflowMode) : BinaryInstruction(opCode) { public readonly StackType OpType = opType; @@ -47,14 +48,9 @@ namespace ICSharpCode.Decompiler.IL Right.WriteTo(output); output.Write(')'); } - - public override InstructionFlags Flags - { - get { return Left.Flags | Right.Flags | InstructionFlags.MayThrow; } - } } - class BinaryComparisonInstruction(OpCode opCode, StackType opType) + public abstract class BinaryComparisonInstruction(OpCode opCode, StackType opType) : BinaryInstruction(opCode) { public readonly StackType OpType = opType; @@ -70,11 +66,6 @@ namespace ICSharpCode.Decompiler.IL Right.WriteTo(output); output.Write(')'); } - - public override InstructionFlags Flags - { - get { return Left.Flags | Right.Flags; } - } } public enum OverflowMode : byte diff --git a/ICSharpCode.Decompiler/IL/Instructions/Block.cs b/ICSharpCode.Decompiler/IL/Instructions/Block.cs index 28f1855ea..206b3e6a8 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Block.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Block.cs @@ -9,10 +9,11 @@ namespace ICSharpCode.Decompiler.IL /// /// A block of IL instructions. /// - class Block() : ILInstruction(OpCode.Block) + partial class Block : ILInstruction { public readonly List Instructions = new List(); + /* public override bool IsPeeking { get { return Instructions.Count > 0 && Instructions[0].IsPeeking; } } public override bool NoResult { get { return true; } } @@ -23,6 +24,7 @@ namespace ICSharpCode.Decompiler.IL Instructions[i] = transformFunc(Instructions[i]); } } + */ /// /// Gets the name of this block. @@ -45,6 +47,7 @@ namespace ICSharpCode.Decompiler.IL output.WriteLine("}"); } + /* public override InstructionFlags Flags { get { @@ -63,7 +66,7 @@ namespace ICSharpCode.Decompiler.IL else finished = true; return this; - } + }*/ } /// @@ -73,11 +76,12 @@ namespace ICSharpCode.Decompiler.IL /// That means that viewed from the outside, the block container has a single entry point (but possibly multiple exit points), /// and the same holds for every block within the container. /// - class BlockContainer() : ILInstruction(OpCode.BlockContainer) + partial class BlockContainer : ILInstruction { public List Blocks = new List(); public Block EntryPoint { get { return Blocks[0]; } } + /* public override bool IsPeeking { get { return EntryPoint.IsPeeking; } } public override bool NoResult { get { return true; } } @@ -89,6 +93,7 @@ namespace ICSharpCode.Decompiler.IL throw new InvalidOperationException("Cannot replace blocks"); } } + */ public override void WriteTo(ITextOutput output) { @@ -102,6 +107,7 @@ namespace ICSharpCode.Decompiler.IL output.WriteLine("}"); } + /* public override InstructionFlags Flags { get @@ -118,6 +124,6 @@ namespace ICSharpCode.Decompiler.IL { finished = false; return this; - } + }*/ } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs index fdfce050b..a2c1930a4 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace ICSharpCode.Decompiler.IL { - class CallInstruction(OpCode opCode, MethodReference methodReference) : ILInstruction(opCode) + public abstract class CallInstruction(OpCode opCode, MethodReference methodReference) : ILInstruction(opCode) { public readonly MethodReference Method = methodReference; public readonly ILInstruction[] Operands = InitOperands(opCode, methodReference); @@ -25,6 +25,7 @@ namespace ICSharpCode.Decompiler.IL return operands; } + /* public override bool IsPeeking { get { return Operands.Length > 0 && Operands[0].IsPeeking; } } public override bool NoResult @@ -40,7 +41,7 @@ namespace ICSharpCode.Decompiler.IL for (int i = 0; i < Operands.Length; i++) { Operands[i] = transformFunc(Operands[i]); } - } + }*/ /// /// Gets/Sets whether the call has the 'tail.' prefix. @@ -73,6 +74,7 @@ namespace ICSharpCode.Decompiler.IL output.Write(')'); } + /* public override InstructionFlags Flags { get @@ -99,6 +101,6 @@ namespace ICSharpCode.Decompiler.IL break; } return this; - } + }*/ } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs index 3440612aa..8b4d74900 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using ICSharpCode.Decompiler.CSharp; namespace ICSharpCode.Decompiler.IL { @@ -20,6 +21,20 @@ namespace ICSharpCode.Decompiler.IL /// public Interval ILRange; + public abstract void WriteTo(ITextOutput output); + + /// + /// 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 TReturn AcceptVisitor(ILVisitor visitor); + + /* /// /// 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 @@ -63,5 +78,6 @@ namespace ICSharpCode.Decompiler.IL internal abstract ILInstruction Inline(InstructionFlags flagsBefore, Stack instructionStack, out bool finished); public abstract void TransformChildren(Func transformFunc); + */ } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs index 26e8f3423..03968cbdc 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs @@ -9,9 +9,14 @@ namespace ICSharpCode.Decompiler.IL /// /// A simple instruction that does not have any arguments. /// - abstract class SimpleInstruction(OpCode opCode) : ILInstruction(opCode) + public abstract class SimpleInstruction(OpCode opCode) : ILInstruction(opCode) { - public override bool IsPeeking { get { return false; } } + public override void WriteTo(ITextOutput output) + { + output.Write(OpCode); + } + + /*public override bool IsPeeking { get { return false; } } public override void TransformChildren(Func transformFunc) { @@ -21,9 +26,10 @@ namespace ICSharpCode.Decompiler.IL { finished = true; // Nothing to do, since we don't have arguments. return this; - } + }*/ } + /* class Nop() : SimpleInstruction(OpCode.Nop) { public override bool NoResult { get { return true; } } @@ -159,5 +165,5 @@ namespace ICSharpCode.Decompiler.IL { get { return InstructionFlags.None; } } - } + }*/ } diff --git a/ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs index a8fd37f6e..32792f604 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs @@ -8,20 +8,21 @@ using System.Threading.Tasks; namespace ICSharpCode.Decompiler.IL { - abstract class UnaryInstruction(OpCode opCode) : ILInstruction(opCode) + public abstract class UnaryInstruction(OpCode opCode) : ILInstruction(opCode) { - public ILInstruction Operand = Pop; + public ILInstruction Argument = Pop; - public sealed override bool IsPeeking { get { return Operand.IsPeeking; } } + //public sealed override bool IsPeeking { get { return Operand.IsPeeking; } } public override void WriteTo(ITextOutput output) { output.Write(OpCode); output.Write('('); - Operand.WriteTo(output); + Argument.WriteTo(output); output.Write(')'); } + /* public override void TransformChildren(Func transformFunc) { Operand = transformFunc(Operand); @@ -31,9 +32,10 @@ namespace ICSharpCode.Decompiler.IL { Operand = Operand.Inline(flagsBefore, instructionStack, out finished); return this; - } + }*/ } + /* class VoidInstruction() : UnaryInstruction(OpCode.Void) { public override bool NoResult { get { return true; } } @@ -111,6 +113,6 @@ namespace ICSharpCode.Decompiler.IL { get { return Operand.Flags | InstructionFlags.MayThrow; } } - } + }*/ } \ No newline at end of file diff --git a/ICSharpCode.Decompiler/IL/StackType.cs b/ICSharpCode.Decompiler/IL/StackType.cs index 8c1571363..0198aff36 100644 --- a/ICSharpCode.Decompiler/IL/StackType.cs +++ b/ICSharpCode.Decompiler/IL/StackType.cs @@ -9,7 +9,7 @@ namespace ICSharpCode.Decompiler.IL /// /// A type for the purpose of stack analysis. /// - enum StackType + public enum StackType { Unknown, /// 32-bit integer