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