diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index 5c8b1c1ae..880b32c1f 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -83,6 +83,7 @@
+
diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs
index 4de264a85..65a8bcf0c 100644
--- a/ICSharpCode.Decompiler/IL/ILReader.cs
+++ b/ICSharpCode.Decompiler/IL/ILReader.cs
@@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.IL
ILInstruction decodedInstruction = DecodeInstruction();
decodedInstruction.ILRange = new Interval(start, reader.Position);
instructionBuilder.Add(decodedInstruction);
- if ((var branch = decodedInstruction as BranchInstruction) != null) {
+ if ((var branch = decodedInstruction as Branch) != null) {
if (branch.TargetILOffset >= reader.Position) {
branchStackDict[branch.TargetILOffset] = stack.ToImmutableArray();
}
@@ -70,7 +70,7 @@ namespace ICSharpCode.Decompiler.IL
}
}
return instructionBuilder.ToImmutable();
- }
+ }
private bool IsUnconditionalBranch(OpCode opCode)
{
@@ -101,7 +101,7 @@ namespace ICSharpCode.Decompiler.IL
return BinaryNumeric(OpCode.BitAnd);
case ILOpCode.Arglist:
stack.Push(StackType.O);
- return new SimpleInstruction(OpCode.Arglist);
+ return new Arglist();
case ILOpCode.Beq:
return DecodeComparisonBranch(false, OpCode.Ceq, OpCode.Ceq, false);
case ILOpCode.Beq_S:
@@ -147,7 +147,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Br_S:
return DecodeUnconditionalBranch(true, OpCode.Branch);
case ILOpCode.Break:
- return new SimpleInstruction(OpCode.Break);
+ return new DebugBreak();
case ILOpCode.Brfalse:
return DecodeConditionalBranch(false, true);
case ILOpCode.Brfalse_S:
@@ -173,7 +173,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Clt_Un:
return Comparison(OpCode.Clt_Un, OpCode.Clt_Un);
case ILOpCode.Ckfinite:
- return new PeekInstruction(OpCode.Ckfinite);
+ return new Ckfinite();
case ILOpCode.Conv_I1:
return Conv(PrimitiveType.I1, OverflowMode.None);
case ILOpCode.Conv_I2:
@@ -247,7 +247,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Div_Un:
return BinaryNumeric(OpCode.Div, OverflowMode.Un);
case ILOpCode.Dup:
- return new PeekInstruction(OpCode.Peek);
+ return new Peek();
case ILOpCode.Endfilter:
throw new NotImplementedException();
case ILOpCode.Endfinally:
@@ -292,7 +292,7 @@ namespace ICSharpCode.Decompiler.IL
return LdcI4(reader.ReadSByte());
case ILOpCode.Ldnull:
stack.Push(StackType.O);
- return new SimpleInstruction(OpCode.LdNull);
+ return new ConstantNull();
case ILOpCode.Ldstr:
return DecodeLdstr();
case ILOpCode.Ldftn:
@@ -337,14 +337,14 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Neg:
return UnaryNumeric(OpCode.Neg);
case ILOpCode.Nop:
- return new SimpleInstruction(OpCode.Nop);
+ return new Nop();
case ILOpCode.Not:
return UnaryNumeric(OpCode.BitNot);
case ILOpCode.Or:
return BinaryNumeric(OpCode.BitOr);
case ILOpCode.Pop:
stack.PopOrDefault();
- return new UnaryInstruction(OpCode.Void);
+ return new VoidInstruction();
case ILOpCode.Rem:
return BinaryNumeric(OpCode.Rem, OverflowMode.None);
case ILOpCode.Rem_Un:
@@ -406,21 +406,36 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldelema:
throw new NotImplementedException();
case ILOpCode.Ldfld:
- throw new NotImplementedException();
+ {
+ stack.PopOrDefault();
+ FieldReference field = (FieldReference)ReadAndDecodeMetadataToken();
+ stack.Push(field.FieldType.GetStackType());
+ return new LoadInstanceField(field);
+ }
case ILOpCode.Ldflda:
- throw new NotImplementedException();
+ stack.PopOrDefault();
+ stack.Push(StackType.Ref);
+ return new LoadInstanceField((FieldReference)ReadAndDecodeMetadataToken(), OpCode.Ldflda);
case ILOpCode.Stfld:
- throw new NotImplementedException();
+ stack.PopOrDefault();
+ stack.PopOrDefault();
+ return new StoreInstanceField((FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldlen:
throw new NotImplementedException();
case ILOpCode.Ldobj:
throw new NotImplementedException();
case ILOpCode.Ldsfld:
- throw new NotImplementedException();
+ {
+ FieldReference field = (FieldReference)ReadAndDecodeMetadataToken();
+ stack.Push(field.FieldType.GetStackType());
+ return new LoadStaticField(field);
+ }
case ILOpCode.Ldsflda:
- throw new NotImplementedException();
+ stack.Push(StackType.Ref);
+ return new LoadStaticField((FieldReference)ReadAndDecodeMetadataToken(), OpCode.Ldsflda);
case ILOpCode.Stsfld:
- throw new NotImplementedException();
+ stack.PopOrDefault();
+ return new StoreStaticField((FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldtoken:
throw new NotImplementedException();
case ILOpCode.Ldvirtftn:
@@ -470,9 +485,9 @@ namespace ICSharpCode.Decompiler.IL
private ILInstruction Ret()
{
if (body.Method.ReturnType.GetStackType() == StackType.Void)
- return new SimpleInstruction(OpCode.Ret);
+ return new RetVoid();
else
- return new UnaryInstruction(OpCode.Ret);
+ return new Ret();
}
private ILInstruction UnaryNumeric(OpCode opCode)
@@ -486,61 +501,61 @@ namespace ICSharpCode.Decompiler.IL
{
stack.Push(StackType.O);
var metadataToken = ReadMetadataToken(ref reader);
- return new ConstantStringInstruction(body.LookupStringToken(metadataToken));
- }
+ return new ConstantString(body.LookupStringToken(metadataToken));
+ }
private ILInstruction LdcI4(int val)
{
stack.Push(StackType.I4);
- return new ConstantI4Instruction(val);
+ return new ConstantI4(val);
}
private ILInstruction LdcI8(long val)
{
stack.Push(StackType.I8);
- return new ConstantI8Instruction(val);
+ return new ConstantI8(val);
}
private ILInstruction LdcF(double val)
{
stack.Push(StackType.F);
- return new ConstantFloatInstruction(val);
+ return new ConstantFloat(val);
}
private ILInstruction Ldarg(ushort v)
{
stack.Push(parameterVariables[v].Type.GetStackType());
- return new LoadVarInstruction(parameterVariables[v]);
- }
+ return new LdLoc(parameterVariables[v]);
+ }
private ILInstruction Ldarga(ushort v)
{
stack.Push(StackType.Ref);
- return new LoadVarInstruction(parameterVariables[v], OpCode.LoadVarAddress);
+ return new LdLoca(parameterVariables[v]);
}
private ILInstruction Starg(ushort v)
{
stack.PopOrDefault();
- return new StoreVarInstruction(parameterVariables[v]);
+ return new StLoc(parameterVariables[v]);
}
private ILInstruction Ldloc(ushort v)
{
stack.Push(localVariables[v].Type.GetStackType());
- return new LoadVarInstruction(localVariables[v]);
+ return new LdLoc(localVariables[v]);
}
private ILInstruction Ldloca(ushort v)
{
stack.Push(StackType.Ref);
- return new LoadVarInstruction(localVariables[v], OpCode.LoadVarAddress);
+ return new LdLoca(localVariables[v]);
}
private ILInstruction Stloc(ushort v)
{
stack.PopOrDefault();
- return new StoreVarInstruction(localVariables[v]);
+ return new StLoc(localVariables[v]);
}
private ILInstruction DecodeConstrainedCall()
@@ -619,7 +634,7 @@ namespace ICSharpCode.Decompiler.IL
if (negate) {
condition = new LogicNotInstruction { Operand = condition };
}
- return new ConditionalBranchInstruction(condition, target);
+ return new ConditionalBranch(condition, target);
}
ILInstruction DecodeConditionalBranch(bool shortForm, bool negate)
@@ -630,14 +645,14 @@ namespace ICSharpCode.Decompiler.IL
if (negate) {
condition = new LogicNotInstruction { Operand = condition };
}
- return new ConditionalBranchInstruction(condition, target);
+ return new ConditionalBranch(condition, target);
}
ILInstruction DecodeUnconditionalBranch(bool shortForm, OpCode opCode)
{
int start = reader.Position - 1;
int target = start + (shortForm ? reader.ReadSByte() : reader.ReadInt32());
- return new BranchInstruction(opCode, target);
+ return new Branch(opCode, target);
}
ILInstruction BinaryNumeric(OpCode opCode, OverflowMode overflowMode = OverflowMode.None)
diff --git a/ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs
index 90ce5c4f1..407097f57 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/BinaryInstruction.cs
@@ -12,6 +12,12 @@ namespace ICSharpCode.Decompiler.IL
public ILInstruction Right = Pop;
public override bool IsPeeking { get { return Left.IsPeeking; } }
+
+ public override void TransformChildren(Func transformFunc)
+ {
+ Left = transformFunc(Left);
+ Right = transformFunc(Right);
+ }
}
class BinaryNumericInstruction(OpCode opCode, StackType opType, OverflowMode overflowMode)
diff --git a/ICSharpCode.Decompiler/IL/Instructions/BranchInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/BranchInstruction.cs
index 325ed4a19..115c02c98 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/BranchInstruction.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/BranchInstruction.cs
@@ -9,7 +9,7 @@ namespace ICSharpCode.Decompiler.IL
///
/// Base class for unconditional and conditional branches.
///
- class BranchInstruction(OpCode opCode, public int TargetILOffset) : ILInstruction(opCode)
+ class Branch(OpCode opCode, public int TargetILOffset) : ILInstruction(opCode)
{
public override bool IsPeeking { get { return false; } }
@@ -19,13 +19,26 @@ namespace ICSharpCode.Decompiler.IL
output.Write(' ');
output.WriteReference(CecilExtensions.OffsetToString(TargetILOffset), TargetILOffset, isLocal: true);
}
+
+ public override bool IsEndReachable
+ {
+ get
+ {
+ // end is reachable for conditional branches, but not unconditional ones
+ return OpCode == OpCode.ConditionalBranch;
+ }
+ }
+
+ public override void TransformChildren(Func transformFunc)
+ {
+ }
}
///
/// Special instruction for unresolved branches.
/// Created by ILReader phase, replaced with TODO when building basic blocks.
///
- class ConditionalBranchInstruction(public ILInstruction Condition, int targetILOffset) : BranchInstruction(OpCode.ConditionalBranch, targetILOffset)
+ class ConditionalBranch(public ILInstruction Condition, int targetILOffset) : Branch(OpCode.ConditionalBranch, targetILOffset)
{
public override bool IsPeeking { get { return Condition.IsPeeking; } }
@@ -36,5 +49,20 @@ namespace ICSharpCode.Decompiler.IL
Condition.WriteTo(output);
output.Write(')');
}
+
+ public override void TransformChildren(Func transformFunc)
+ {
+ Condition = transformFunc(Condition);
+ }
+ }
+
+ class RetVoid() : SimpleInstruction(OpCode.Ret)
+ {
+ public override bool IsEndReachable { get { return false; } }
+ }
+
+ class Ret() : UnaryInstruction(OpCode.Ret)
+ {
+ public override bool IsEndReachable { get { return false; } }
}
}
diff --git a/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
index af31af6e7..5d2eb7f11 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
@@ -24,6 +24,21 @@ namespace ICSharpCode.Decompiler.IL
public override bool IsPeeking { get { return Operands.Length > 0 && Operands[0].IsPeeking; } }
+ public override bool NoResult
+ {
+ get
+ {
+ return Method.ReturnType.GetStackType() == StackType.Void;
+ }
+ }
+
+ public override void TransformChildren(Func transformFunc)
+ {
+ for (int i = 0; i < Operands.Length; i++) {
+ Operands[i] = transformFunc(Operands[i]);
+ }
+ }
+
///
/// Gets/Sets whether the call has the 'tail.' prefix.
///
diff --git a/ICSharpCode.Decompiler/IL/Instructions/FieldAccess.cs b/ICSharpCode.Decompiler/IL/Instructions/FieldAccess.cs
new file mode 100644
index 000000000..c736b6279
--- /dev/null
+++ b/ICSharpCode.Decompiler/IL/Instructions/FieldAccess.cs
@@ -0,0 +1,88 @@
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ICSharpCode.Decompiler.IL
+{
+ class LoadStaticField(FieldReference field, OpCode opCode = OpCode.Ldsfld) : UnaryInstruction(opCode), ISupportsVolatilePrefix
+ {
+ public readonly FieldReference Field = field;
+
+ public bool IsVolatile { get; set; }
+
+ public override void WriteTo(ITextOutput output)
+ {
+ if (IsVolatile)
+ output.Write("volatile.");
+ output.Write(OpCode);
+ output.Write(' ');
+ Disassembler.DisassemblerHelpers.WriteOperand(output, Field);
+ }
+ }
+
+ class StoreStaticField(FieldReference field) : UnaryInstruction(OpCode.Stsfld), ISupportsVolatilePrefix
+ {
+ public readonly FieldReference Field = field;
+
+ public bool IsVolatile { get; set; }
+
+ public override bool NoResult { get { return true; } }
+
+ public override void WriteTo(ITextOutput output)
+ {
+ if (IsVolatile)
+ output.Write("volatile.");
+ output.Write(OpCode);
+ output.Write(' ');
+ Disassembler.DisassemblerHelpers.WriteOperand(output, Field);
+ output.Write('(');
+ Operand.WriteTo(output);
+ output.Write(')');
+ }
+ }
+
+ class LoadInstanceField(FieldReference field, OpCode opCode = OpCode.Ldfld) : UnaryInstruction(opCode), ISupportsVolatilePrefix
+ {
+ public readonly FieldReference Field = field;
+
+ public bool IsVolatile { get; set; }
+
+ public override void WriteTo(ITextOutput output)
+ {
+ if (IsVolatile)
+ output.Write("volatile.");
+ output.Write(OpCode);
+ output.Write(' ');
+ output.WriteReference(Field.Name, Field);
+ output.Write('(');
+ Operand.WriteTo(output);
+ output.Write(')');
+ }
+ }
+
+ class StoreInstanceField(FieldReference field, OpCode opCode = OpCode.Ldfld) : BinaryInstruction(opCode), ISupportsVolatilePrefix
+ {
+ public readonly FieldReference Field = field;
+
+ public bool IsVolatile { get; set; }
+
+ public override bool NoResult { get { return true; } }
+
+ public override void WriteTo(ITextOutput output)
+ {
+ if (IsVolatile)
+ output.Write("volatile.");
+ output.Write(OpCode);
+ output.Write(' ');
+ output.WriteReference(Field.Name, Field);
+ output.Write('(');
+ Left.WriteTo(output);
+ output.Write(", ");
+ Right.WriteTo(output);
+ output.Write(')');
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
index e6077a8d1..c98027e8c 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
@@ -11,8 +11,8 @@ namespace ICSharpCode.Decompiler.IL
///
public abstract class ILInstruction(public readonly OpCode OpCode)
{
- public static readonly ILInstruction Nop = new SimpleInstruction(OpCode.Nop);
- public static readonly ILInstruction Pop = new SimpleInstruction(OpCode.Pop);
+ public static readonly ILInstruction Nop = new Nop();
+ public static readonly ILInstruction Pop = new Pop();
///
/// Gets the ILRange for this instruction alone, ignoring the operands.
@@ -26,6 +26,30 @@ namespace ICSharpCode.Decompiler.IL
///
public abstract bool IsPeeking { get; }
- public abstract void WriteTo(ITextOutput output);
+ ///
+ /// Gets whether the instruction produces no result.
+ /// Instructions without result may not be used as arguments to other instructions;
+ /// and do not result in a stack push when used as a top-level instruction within a block.
+ ///
+ public virtual bool NoResult
+ {
+ get { return false; }
+ }
+
+ ///
+ /// Gets whether the end point of this instruction is reachable from the start point.
+ /// Returns false if the instruction performs an unconditional branch, or always throws an exception.
+ ///
+ public virtual bool IsEndReachable
+ {
+ get { return true; }
+ }
+
+ public virtual void WriteTo(ITextOutput output)
+ {
+ output.Write(OpCode);
+ }
+
+ public abstract void TransformChildren(Func transformFunc);
}
}
diff --git a/ICSharpCode.Decompiler/IL/Instructions/OpCode.cs b/ICSharpCode.Decompiler/IL/Instructions/OpCode.cs
index 6d994207a..663d54741 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/OpCode.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/OpCode.cs
@@ -8,28 +8,26 @@ namespace ICSharpCode.Decompiler.IL
{
public enum OpCode
{
- ///
- /// A instruction that could not be decoded correctly.
- /// Invalid instructions may appear in unreachable code.
- ///
- Invalid,
///
/// No operation. Takes 0 arguments and returns void.
+ ///
///
Nop,
///
/// Pops the top of the evaluation stack and returns the value.
/// Does not correspond to any IL instruction, but encodes the implicit stack use by the IL instruction.
+ ///
///
Pop,
///
/// Peeks at the top of the evaluation stack and returns the value.
- /// Corresponds to IL 'dup'.
+ /// 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,
///
@@ -79,24 +77,24 @@ namespace ICSharpCode.Decompiler.IL
///
BitNot,
///
- /// Retrieves the RuntimeArgumentHandle
+ /// Retrieves the RuntimeArgumentHandle.
///
Arglist,
///
/// if (cond) goto target;
- ///
+ ///
///
ConditionalBranch,
///
/// goto target;
- ///
+ ///
///
Branch,
Leave,
///
/// Breakpoint instruction.
///
- Break,
+ DebugBreak,
///
/// Compare equal.
/// Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.
@@ -149,33 +147,33 @@ namespace ICSharpCode.Decompiler.IL
Conv,
///
/// Loads the value of a variable. (ldarg/ldloc)
- ///
+ ///
///
- LoadVar,
+ LdLoc,
///
- /// Loads the address of a variable as managed ref. (ldarga/ldloca)
- ///
+ /// Loads the address of a variable. (ldarga/ldloca)
+ ///
///
- LoadVarAddress,
+ LdLoca,
///
/// Stores a value into a variable. (starg/stloc)
- ///
+ ///
///
- StoreVar,
+ StLoc,
///
- /// Loads a constant string.
+ /// Loads a constant string.
///
LdStr,
///
- /// Loads a constant 32-bit integer.
+ /// Loads a constant 32-bit integer.
///
LdcI4,
///
- /// Loads a constant 64-bit integer.
+ /// Loads a constant 64-bit integer.
///
LdcI8,
///
- /// Loads a constant floating point number.
+ /// Loads a constant floating point number.
///
LdcF,
///
@@ -184,7 +182,7 @@ namespace ICSharpCode.Decompiler.IL
LdNull,
///
/// Returns from the current method or lambda.
- /// or , depending on whether
+ /// or , depending on whether
/// the method has return type void.
///
Ret,
@@ -196,5 +194,29 @@ namespace ICSharpCode.Decompiler.IL
/// Shift right.
///
Shr,
+ ///
+ /// Load instance field.
+ ///
+ Ldfld,
+ ///
+ /// Load instance field address.
+ ///
+ Ldflda,
+ ///
+ /// Store to instance field.
+ ///
+ Stfld,
+ ///
+ /// Load static field.
+ ///
+ Ldsfld,
+ ///
+ /// Load static field address.
+ ///
+ Ldsflda,
+ ///
+ /// Store to static field.
+ ///
+ Stsfld,
}
}
diff --git a/ICSharpCode.Decompiler/IL/Instructions/Prefix.cs b/ICSharpCode.Decompiler/IL/Instructions/Prefix.cs
index 15d1dd579..b33506d7a 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/Prefix.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/Prefix.cs
@@ -6,13 +6,16 @@ using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
- interface ISupportsMemoryPrefix
+ interface ISupportsMemoryPrefix : ISupportsVolatilePrefix
{
///
/// Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.
///
byte UnalignedPrefix { get; set; }
+ }
+ interface ISupportsVolatilePrefix
+ {
///
/// Gets/Sets whether the memory access is volatile.
///
diff --git a/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
index 9f7310f34..b37461adf 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
@@ -7,29 +7,47 @@ using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
///
- /// A simple instruction that does not pop any elements from the stack.
+ /// A simple instruction that does not have any arguments.
///
- class SimpleInstruction(OpCode opCode) : ILInstruction(opCode)
+ abstract class SimpleInstruction(OpCode opCode) : ILInstruction(opCode)
{
public override bool IsPeeking { get { return false; } }
- public override void WriteTo(ITextOutput output)
+ public override void TransformChildren(Func transformFunc)
{
- output.Write(OpCode);
}
}
- class PeekInstruction(OpCode opCode = OpCode.Peek) : ILInstruction(opCode)
+ class Nop() : SimpleInstruction(OpCode.Nop)
+ {
+ public override bool NoResult { get { return true; } }
+ }
+
+ class Pop() : SimpleInstruction(OpCode.Pop)
+ {
+ }
+
+ class Peek() : SimpleInstruction(OpCode.Peek)
{
public override bool IsPeeking { get { return true; } }
+ }
- public override void WriteTo(ITextOutput output)
- {
- output.Write(OpCode);
- }
+ class Ckfinite() : SimpleInstruction(OpCode.Ckfinite)
+ {
+ public override bool IsPeeking { get { return true; } }
+ public override bool NoResult { get { return true; } }
+ }
+
+ class Arglist() : SimpleInstruction(OpCode.Arglist)
+ {
}
- class ConstantStringInstruction(public readonly string Value) : SimpleInstruction(OpCode.LdStr)
+ class DebugBreak() : SimpleInstruction(OpCode.DebugBreak)
+ {
+ public override bool NoResult { get { return true; } }
+ }
+
+ class ConstantString(public readonly string Value) : SimpleInstruction(OpCode.LdStr)
{
public override void WriteTo(ITextOutput output)
{
@@ -37,7 +55,7 @@ namespace ICSharpCode.Decompiler.IL
}
}
- class ConstantI4Instruction(public readonly int Value) : SimpleInstruction(OpCode.LdcI4)
+ class ConstantI4(public readonly int Value) : SimpleInstruction(OpCode.LdcI4)
{
public override void WriteTo(ITextOutput output)
{
@@ -45,7 +63,7 @@ namespace ICSharpCode.Decompiler.IL
}
}
- class ConstantI8Instruction(public readonly long Value) : SimpleInstruction(OpCode.LdcI8)
+ class ConstantI8(public readonly long Value) : SimpleInstruction(OpCode.LdcI8)
{
public override void WriteTo(ITextOutput output)
{
@@ -53,11 +71,15 @@ namespace ICSharpCode.Decompiler.IL
}
}
- class ConstantFloatInstruction(public readonly double Value) : SimpleInstruction(OpCode.LdcI8)
+ class ConstantFloat(public readonly double Value) : SimpleInstruction(OpCode.LdcI8)
{
public override void WriteTo(ITextOutput output)
{
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
}
}
+
+ class ConstantNull() : SimpleInstruction(OpCode.LdNull)
+ {
+ }
}
diff --git a/ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs
index 409a7fc75..f4f8f822b 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs
@@ -6,11 +6,11 @@ using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
- class UnaryInstruction(OpCode opCode) : ILInstruction(opCode)
+ abstract class UnaryInstruction(OpCode opCode) : ILInstruction(opCode)
{
public ILInstruction Operand = Pop;
- public override bool IsPeeking { get { return Operand.IsPeeking; } }
+ public sealed override bool IsPeeking { get { return Operand.IsPeeking; } }
public override void WriteTo(ITextOutput output)
{
@@ -19,6 +19,16 @@ namespace ICSharpCode.Decompiler.IL
Operand.WriteTo(output);
output.Write(')');
}
+
+ public override void TransformChildren(Func transformFunc)
+ {
+ Operand = transformFunc(Operand);
+ }
+ }
+
+ class VoidInstruction() : UnaryInstruction(OpCode.Void)
+ {
+ public override bool NoResult { get { return true; } }
}
class LogicNotInstruction() : UnaryInstruction(OpCode.LogicNot)
diff --git a/ICSharpCode.Decompiler/IL/Instructions/VarInstructions.cs b/ICSharpCode.Decompiler/IL/Instructions/VarInstructions.cs
index 5b4b5c973..705f5e4b2 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/VarInstructions.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/VarInstructions.cs
@@ -6,24 +6,25 @@ using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.IL
{
- class LoadVarInstruction(public readonly ILVariable Variable, OpCode opCode = OpCode.LoadVar) : ILInstruction(opCode)
+ class LdLoc(public readonly ILVariable Variable) : SimpleInstruction(OpCode.LdLoc)
{
- public override bool IsPeeking { get { return false; } }
-
public override void WriteTo(ITextOutput output)
{
- if (OpCode != OpCode.LoadVar) {
- output.Write(OpCode);
- output.Write(' ');
- }
output.WriteReference(Variable.ToString(), Variable, isLocal: true);
}
}
- class StoreVarInstruction(public readonly ILVariable Variable) : UnaryInstruction(OpCode.StoreVar)
+ class LdLoca(public readonly ILVariable Variable) : SimpleInstruction(OpCode.LdLoca)
{
- public override bool IsPeeking { get { return false; } }
+ public override void WriteTo(ITextOutput output)
+ {
+ output.Write("ref ");
+ output.WriteReference(Variable.ToString(), Variable, isLocal: true);
+ }
+ }
+ class StLoc(public readonly ILVariable Variable) : UnaryInstruction(OpCode.StLoc)
+ {
public override void WriteTo(ITextOutput output)
{
output.WriteReference(Variable.ToString(), Variable, isLocal: true);