// Copyright (c) 2014 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL
{
///
/// Enum representing the type of an .
///
public enum OpCode
{
/// Represents invalid IL. Semantically, this instruction is considered to throw some kind of exception.
InvalidBranch,
/// Represents invalid IL. Semantically, this instruction is considered to produce some kind of value.
InvalidExpression,
/// No operation. Takes 0 arguments and returns void.
Nop,
/// A container of IL blocks.
ILFunction,
/// A container of IL blocks.
BlockContainer,
/// A block of IL instructions.
Block,
/// A region where a pinned variable is used (initial representation of future fixed statement).
PinnedRegion,
/// 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,
/// Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.
BinaryNumericInstruction,
/// Common instruction for compound assignments.
CompoundAssignmentInstruction,
/// Bitwise NOT
BitNot,
/// Retrieves the RuntimeArgumentHandle.
Arglist,
/// Unconditional branch. goto target;
Branch,
/// Unconditional branch to end of block container. goto container_end;, often break;
Leave,
/// If statement / conditional expression. if (condition) trueExpr else falseExpr
IfInstruction,
/// Null coalescing operator expression. if.notnull(valueInst, fallbackInst)
NullCoalescingInstruction,
/// Switch statement
SwitchInstruction,
/// Switch section within a switch statement
SwitchSection,
/// Try-catch statement.
TryCatch,
/// Catch handler within a try-catch statement.
TryCatchHandler,
/// Try-finally statement
TryFinally,
/// Try-fault statement
TryFault,
/// Breakpoint instruction
DebugBreak,
/// Comparison. The inputs must be both integers; or both floats; or both object references. Object references can only be compared for equality or inequality. Floating-point comparisons evaluate to 0 (false) when an input is NaN, except for 'NaN != NaN' which evaluates to 1 (true).
Comp,
/// Non-virtual method call.
Call,
/// Virtual method call.
CallVirt,
/// Checks that the input float 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,
/// Stores the value into an anonymous temporary variable, and returns the address of that variable.
AddressOf,
/// 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 a constant decimal.
LdcDecimal,
/// Loads the null reference.
LdNull,
/// Load method pointer
LdFtn,
/// Load method pointer
LdVirtFtn,
/// Loads runtime representation of metadata token
LdTypeToken,
/// Loads runtime representation of metadata token
LdMemberToken,
/// Allocates space in the stack frame
LocAlloc,
/// Returns from the current method or lambda. Only used when returning a value; void returns are represented using a 'leave' instruction.
Return,
/// Load address of instance field
LdFlda,
/// Load static field address
LdsFlda,
/// Casts an object to a class.
CastClass,
/// Test if object is instance of class or interface.
IsInst,
/// Indirect load (ref/pointer dereference).
LdObj,
/// Indirect store (store to ref/pointer).
StObj,
/// Boxes a value.
Box,
/// Compute address inside box.
Unbox,
/// Unbox a value.
UnboxAny,
/// Creates an object instance and calls the constructor.
NewObj,
/// Creates an array instance.
NewArr,
/// Returns the default value for a type.
DefaultValue,
/// Throws an exception.
Throw,
/// Rethrows the current exception.
Rethrow,
/// Gets the size of a type in bytes.
SizeOf,
/// Returns the length of an array as 'native unsigned int'.
LdLen,
/// Load address of array element.
LdElema,
/// Converts an array pointer (O) to a reference to the first element, or to a null reference if the array is null or empty.
/// Also used to convert a string to a reference to the first character.
ArrayToPointer,
/// Push a typed reference of type class onto the stack.
MakeRefAny,
/// Push the type token stored in a typed reference.
RefAnyType,
/// Push the address stored in a typed reference.
RefAnyValue,
/// Yield an element from an iterator.
YieldReturn,
/// Matches any node
AnyNode,
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Instruction without any arguments
public abstract partial class SimpleInstruction : ILInstruction
{
protected SimpleInstruction(OpCode opCode) : base(opCode)
{
}
protected sealed override int GetChildCount()
{
return 0;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (SimpleInstruction)ShallowClone();
return clone;
}
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.None;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.None;
}
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Instruction with a single argument
public abstract partial class UnaryInstruction : ILInstruction
{
protected UnaryInstruction(OpCode opCode, ILInstruction argument) : base(opCode)
{
this.Argument = argument;
}
public static readonly SlotInfo ArgumentSlot = new SlotInfo("Argument", canInlineInto: true);
ILInstruction argument;
public ILInstruction Argument {
get { return this.argument; }
set {
ValidateChild(value);
SetChildInstruction(ref this.argument, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.argument;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Argument = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return ArgumentSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (UnaryInstruction)ShallowClone();
clone.Argument = this.argument.Clone();
return clone;
}
protected override InstructionFlags ComputeFlags()
{
return argument.Flags | InstructionFlags.None;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.None;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write('(');
this.argument.WriteTo(output);
output.Write(')');
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Instruction with two arguments: Left and Right
public abstract partial class BinaryInstruction : ILInstruction
{
protected BinaryInstruction(OpCode opCode, ILInstruction left, ILInstruction right) : base(opCode)
{
this.Left = left;
this.Right = right;
}
public static readonly SlotInfo LeftSlot = new SlotInfo("Left", canInlineInto: true);
ILInstruction left;
public ILInstruction Left {
get { return this.left; }
set {
ValidateChild(value);
SetChildInstruction(ref this.left, value, 0);
}
}
public static readonly SlotInfo RightSlot = new SlotInfo("Right", canInlineInto: true);
ILInstruction right;
public ILInstruction Right {
get { return this.right; }
set {
ValidateChild(value);
SetChildInstruction(ref this.right, value, 1);
}
}
protected sealed override int GetChildCount()
{
return 2;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.left;
case 1:
return this.right;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Left = value;
break;
case 1:
this.Right = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return LeftSlot;
case 1:
return RightSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (BinaryInstruction)ShallowClone();
clone.Left = this.left.Clone();
clone.Right = this.right.Clone();
return clone;
}
protected override InstructionFlags ComputeFlags()
{
return left.Flags | right.Flags | InstructionFlags.None;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.None;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write('(');
this.left.WriteTo(output);
output.Write(", ");
this.right.WriteTo(output);
output.Write(')');
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Instruction with a list of arguments.
public abstract partial class CallInstruction : ILInstruction
{
protected CallInstruction(OpCode opCode, params ILInstruction[] arguments) : base(opCode)
{
this.Arguments = new InstructionCollection(this, 0);
this.Arguments.AddRange(arguments);
}
public static readonly SlotInfo ArgumentsSlot = new SlotInfo("Arguments", canInlineInto: true);
public InstructionCollection Arguments { get; private set; }
protected sealed override int GetChildCount()
{
return Arguments.Count;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
default:
return this.Arguments[index - 0];
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
default:
this.Arguments[index - 0] = value;
break;
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
default:
return ArgumentsSlot;
}
}
public sealed override ILInstruction Clone()
{
var clone = (CallInstruction)ShallowClone();
clone.Arguments = new InstructionCollection(clone, 0);
clone.Arguments.AddRange(this.Arguments.Select(arg => arg.Clone()));
return clone;
}
protected override InstructionFlags ComputeFlags()
{
return Arguments.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags) | InstructionFlags.MayThrow | InstructionFlags.SideEffect;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayThrow | InstructionFlags.SideEffect;
}
}
}
}
namespace ICSharpCode.Decompiler.IL.Patterns
{
/// Base class for pattern matching in ILAst.
public abstract partial class PatternInstruction : ILInstruction
{
protected PatternInstruction(OpCode opCode) : base(opCode)
{
}
public override StackType ResultType { get { return StackType.Unknown; } }
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Represents invalid IL. Semantically, this instruction is considered to throw some kind of exception.
public sealed partial class InvalidBranch : SimpleInstruction
{
public InvalidBranch() : base(OpCode.InvalidBranch)
{
}
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayThrow | InstructionFlags.SideEffect | InstructionFlags.EndPointUnreachable;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayThrow | InstructionFlags.SideEffect | InstructionFlags.EndPointUnreachable;
}
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitInvalidBranch(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitInvalidBranch(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitInvalidBranch(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as InvalidBranch;
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Represents invalid IL. Semantically, this instruction is considered to produce some kind of value.
public sealed partial class InvalidExpression : SimpleInstruction
{
public InvalidExpression() : base(OpCode.InvalidExpression)
{
}
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayThrow | InstructionFlags.SideEffect;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayThrow | InstructionFlags.SideEffect;
}
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitInvalidExpression(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitInvalidExpression(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitInvalidExpression(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as InvalidExpression;
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// No operation. Takes 0 arguments and returns void.
public sealed partial class Nop : SimpleInstruction
{
public Nop() : base(OpCode.Nop)
{
}
public override StackType ResultType { get { return StackType.Void; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitNop(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitNop(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitNop(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Nop;
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// A container of IL blocks.
public sealed partial class ILFunction : ILInstruction
{
public static readonly SlotInfo BodySlot = new SlotInfo("Body");
ILInstruction body;
public ILInstruction Body {
get { return this.body; }
set {
ValidateChild(value);
SetChildInstruction(ref this.body, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.body;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Body = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return BodySlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (ILFunction)ShallowClone();
clone.Body = this.body.Clone();
clone.CloneVariables();
return clone;
}
public override StackType ResultType { get { return StackType.O; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitILFunction(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitILFunction(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitILFunction(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as ILFunction;
return o != null && this.body.PerformMatch(o.body, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// A container of IL blocks.
public sealed partial class BlockContainer : ILInstruction
{
public override StackType ResultType { get { return StackType.Void; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitBlockContainer(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitBlockContainer(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitBlockContainer(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as BlockContainer;
return o != null && Patterns.ListMatch.DoMatch(this.Blocks, o.Blocks, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// A block of IL instructions.
public sealed partial class Block : ILInstruction
{
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitBlock(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitBlock(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitBlock(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Block;
return o != null && this.Type == o.Type && Patterns.ListMatch.DoMatch(this.Instructions, o.Instructions, ref match) && this.FinalInstruction.PerformMatch(o.FinalInstruction, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// A region where a pinned variable is used (initial representation of future fixed statement).
public sealed partial class PinnedRegion : ILInstruction, IStoreInstruction
{
public PinnedRegion(ILVariable variable, ILInstruction init, ILInstruction body) : base(OpCode.PinnedRegion)
{
Debug.Assert(variable != null);
this.variable = variable;
this.Init = init;
this.Body = body;
}
public override StackType ResultType { get { return StackType.Void; } }
ILVariable variable;
public ILVariable Variable {
get { return variable; }
set {
Debug.Assert(value != null);
if (IsConnected)
variable.RemoveStoreInstruction(this);
variable = value;
if (IsConnected)
variable.AddStoreInstruction(this);
}
}
public int IndexInStoreInstructionList { get; set; } = -1;
int IInstructionWithVariableOperand.IndexInVariableInstructionMapping {
get { return ((IStoreInstruction)this).IndexInStoreInstructionList; }
set { ((IStoreInstruction)this).IndexInStoreInstructionList = value; }
}
protected override void Connected()
{
base.Connected();
variable.AddStoreInstruction(this);
}
protected override void Disconnected()
{
variable.RemoveStoreInstruction(this);
base.Disconnected();
}
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function));
}
public static readonly SlotInfo InitSlot = new SlotInfo("Init", canInlineInto: true);
ILInstruction init;
public ILInstruction Init {
get { return this.init; }
set {
ValidateChild(value);
SetChildInstruction(ref this.init, value, 0);
}
}
public static readonly SlotInfo BodySlot = new SlotInfo("Body");
ILInstruction body;
public ILInstruction Body {
get { return this.body; }
set {
ValidateChild(value);
SetChildInstruction(ref this.body, value, 1);
}
}
protected sealed override int GetChildCount()
{
return 2;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.init;
case 1:
return this.body;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Init = value;
break;
case 1:
this.Body = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return InitSlot;
case 1:
return BodySlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (PinnedRegion)ShallowClone();
clone.Init = this.init.Clone();
clone.Body = this.body.Clone();
return clone;
}
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayWriteLocals | init.Flags | body.Flags;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayWriteLocals;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
variable.WriteTo(output);
output.Write('(');
this.init.WriteTo(output);
output.Write(", ");
this.body.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitPinnedRegion(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitPinnedRegion(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitPinnedRegion(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as PinnedRegion;
return o != null && variable == o.variable && this.init.PerformMatch(o.init, ref match) && this.body.PerformMatch(o.body, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// 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
{
public LogicNot(ILInstruction argument) : base(OpCode.LogicNot, argument)
{
}
public override StackType ResultType { get { return StackType.I4; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLogicNot(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLogicNot(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLogicNot(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LogicNot;
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Common instruction for add, sub, mul, div, rem, bit.and, bit.or, bit.xor, shl and shr.
public sealed partial class BinaryNumericInstruction : BinaryInstruction
{
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitBinaryNumericInstruction(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitBinaryNumericInstruction(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitBinaryNumericInstruction(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as BinaryNumericInstruction;
return o != null && this.Left.PerformMatch(o.Left, ref match) && this.Right.PerformMatch(o.Right, ref match) && CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Common instruction for compound assignments.
public sealed partial class CompoundAssignmentInstruction : ILInstruction
{
public static readonly SlotInfo TargetSlot = new SlotInfo("Target", canInlineInto: true);
ILInstruction target;
public ILInstruction Target {
get { return this.target; }
set {
ValidateChild(value);
SetChildInstruction(ref this.target, value, 0);
}
}
public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true);
ILInstruction value;
public ILInstruction Value {
get { return this.value; }
set {
ValidateChild(value);
SetChildInstruction(ref this.value, value, 1);
}
}
protected sealed override int GetChildCount()
{
return 2;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.target;
case 1:
return this.value;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Target = value;
break;
case 1:
this.Value = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return TargetSlot;
case 1:
return ValueSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (CompoundAssignmentInstruction)ShallowClone();
clone.Target = this.target.Clone();
clone.Value = this.value.Clone();
return clone;
}
readonly IType type;
/// Returns the type operand.
public IType Type { get { return type; } }
public override StackType ResultType { get { return type.GetStackType(); } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitCompoundAssignmentInstruction(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitCompoundAssignmentInstruction(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitCompoundAssignmentInstruction(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as CompoundAssignmentInstruction;
return o != null && this.target.PerformMatch(o.target, ref match) && this.value.PerformMatch(o.value, ref match) && type.Equals(o.type) && CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Bitwise NOT
public sealed partial class BitNot : UnaryInstruction
{
public BitNot(ILInstruction argument) : base(OpCode.BitNot, argument)
{
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitBitNot(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitBitNot(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitBitNot(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as BitNot;
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Retrieves the RuntimeArgumentHandle.
public sealed partial class Arglist : SimpleInstruction
{
public Arglist() : base(OpCode.Arglist)
{
}
public override StackType ResultType { get { return StackType.O; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitArglist(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitArglist(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitArglist(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Arglist;
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Unconditional branch. goto target;
public sealed partial class Branch : SimpleInstruction
{
public override StackType ResultType { get { return StackType.Void; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitBranch(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitBranch(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitBranch(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Branch;
return o != null && this.TargetBlock == o.TargetBlock;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Unconditional branch to end of block container. goto container_end;, often break;
public sealed partial class Leave : SimpleInstruction
{
public override StackType ResultType { get { return StackType.Void; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLeave(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLeave(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLeave(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Leave;
return o != null && this.TargetContainer == o.TargetContainer;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// If statement / conditional expression. if (condition) trueExpr else falseExpr
public sealed partial class IfInstruction : ILInstruction
{
public static readonly SlotInfo ConditionSlot = new SlotInfo("Condition", canInlineInto: true);
ILInstruction condition;
public ILInstruction Condition {
get { return this.condition; }
set {
ValidateChild(value);
SetChildInstruction(ref this.condition, value, 0);
}
}
public static readonly SlotInfo TrueInstSlot = new SlotInfo("TrueInst");
ILInstruction trueInst;
public ILInstruction TrueInst {
get { return this.trueInst; }
set {
ValidateChild(value);
SetChildInstruction(ref this.trueInst, value, 1);
}
}
public static readonly SlotInfo FalseInstSlot = new SlotInfo("FalseInst");
ILInstruction falseInst;
public ILInstruction FalseInst {
get { return this.falseInst; }
set {
ValidateChild(value);
SetChildInstruction(ref this.falseInst, value, 2);
}
}
protected sealed override int GetChildCount()
{
return 3;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.condition;
case 1:
return this.trueInst;
case 2:
return this.falseInst;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Condition = value;
break;
case 1:
this.TrueInst = value;
break;
case 2:
this.FalseInst = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return ConditionSlot;
case 1:
return TrueInstSlot;
case 2:
return FalseInstSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (IfInstruction)ShallowClone();
clone.Condition = this.condition.Clone();
clone.TrueInst = this.trueInst.Clone();
clone.FalseInst = this.falseInst.Clone();
return clone;
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitIfInstruction(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitIfInstruction(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitIfInstruction(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as IfInstruction;
return o != null && this.condition.PerformMatch(o.condition, ref match) && this.trueInst.PerformMatch(o.trueInst, ref match) && this.falseInst.PerformMatch(o.falseInst, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Null coalescing operator expression. if.notnull(valueInst, fallbackInst)
public sealed partial class NullCoalescingInstruction : ILInstruction
{
public static readonly SlotInfo ValueInstSlot = new SlotInfo("ValueInst");
ILInstruction valueInst;
public ILInstruction ValueInst {
get { return this.valueInst; }
set {
ValidateChild(value);
SetChildInstruction(ref this.valueInst, value, 0);
}
}
public static readonly SlotInfo FallbackInstSlot = new SlotInfo("FallbackInst");
ILInstruction fallbackInst;
public ILInstruction FallbackInst {
get { return this.fallbackInst; }
set {
ValidateChild(value);
SetChildInstruction(ref this.fallbackInst, value, 1);
}
}
protected sealed override int GetChildCount()
{
return 2;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.valueInst;
case 1:
return this.fallbackInst;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.ValueInst = value;
break;
case 1:
this.FallbackInst = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return ValueInstSlot;
case 1:
return FallbackInstSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (NullCoalescingInstruction)ShallowClone();
clone.ValueInst = this.valueInst.Clone();
clone.FallbackInst = this.fallbackInst.Clone();
return clone;
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitNullCoalescingInstruction(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitNullCoalescingInstruction(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitNullCoalescingInstruction(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as NullCoalescingInstruction;
return o != null && this.valueInst.PerformMatch(o.valueInst, ref match) && this.fallbackInst.PerformMatch(o.fallbackInst, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Switch statement
public sealed partial class SwitchInstruction : ILInstruction
{
public override StackType ResultType { get { return StackType.Void; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitSwitchInstruction(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitSwitchInstruction(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitSwitchInstruction(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as SwitchInstruction;
return o != null && Value.PerformMatch(o.Value, ref match) && DefaultBody.PerformMatch(o.DefaultBody, ref match) && Patterns.ListMatch.DoMatch(this.Sections, o.Sections, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Switch section within a switch statement
public sealed partial class SwitchSection : ILInstruction
{
public static readonly SlotInfo BodySlot = new SlotInfo("Body");
ILInstruction body;
public ILInstruction Body {
get { return this.body; }
set {
ValidateChild(value);
SetChildInstruction(ref this.body, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.body;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Body = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return BodySlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (SwitchSection)ShallowClone();
clone.Body = this.body.Clone();
return clone;
}
public override StackType ResultType { get { return StackType.Void; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitSwitchSection(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitSwitchSection(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitSwitchSection(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as SwitchSection;
return o != null && this.body.PerformMatch(o.body, ref match) && this.Labels.Intervals.SequenceEqual(o.Labels.Intervals);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Try-catch statement.
public sealed partial class TryCatch : TryInstruction
{
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitTryCatch(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitTryCatch(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitTryCatch(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as TryCatch;
return o != null && TryBlock.PerformMatch(o.TryBlock, ref match) && Patterns.ListMatch.DoMatch(Handlers, o.Handlers, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Catch handler within a try-catch statement.
public sealed partial class TryCatchHandler : ILInstruction, IStoreInstruction
{
public TryCatchHandler(ILInstruction filter, ILInstruction body, ILVariable variable) : base(OpCode.TryCatchHandler)
{
this.Filter = filter;
this.Body = body;
Debug.Assert(variable != null);
this.variable = variable;
}
public static readonly SlotInfo FilterSlot = new SlotInfo("Filter");
ILInstruction filter;
public ILInstruction Filter {
get { return this.filter; }
set {
ValidateChild(value);
SetChildInstruction(ref this.filter, value, 0);
}
}
public static readonly SlotInfo BodySlot = new SlotInfo("Body");
ILInstruction body;
public ILInstruction Body {
get { return this.body; }
set {
ValidateChild(value);
SetChildInstruction(ref this.body, value, 1);
}
}
protected sealed override int GetChildCount()
{
return 2;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.filter;
case 1:
return this.body;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Filter = value;
break;
case 1:
this.Body = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return FilterSlot;
case 1:
return BodySlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (TryCatchHandler)ShallowClone();
clone.Filter = this.filter.Clone();
clone.Body = this.body.Clone();
return clone;
}
ILVariable variable;
public ILVariable Variable {
get { return variable; }
set {
Debug.Assert(value != null);
if (IsConnected)
variable.RemoveStoreInstruction(this);
variable = value;
if (IsConnected)
variable.AddStoreInstruction(this);
}
}
public int IndexInStoreInstructionList { get; set; } = -1;
int IInstructionWithVariableOperand.IndexInVariableInstructionMapping {
get { return ((IStoreInstruction)this).IndexInStoreInstructionList; }
set { ((IStoreInstruction)this).IndexInStoreInstructionList = value; }
}
protected override void Connected()
{
base.Connected();
variable.AddStoreInstruction(this);
}
protected override void Disconnected()
{
variable.RemoveStoreInstruction(this);
base.Disconnected();
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitTryCatchHandler(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitTryCatchHandler(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitTryCatchHandler(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as TryCatchHandler;
return o != null && this.filter.PerformMatch(o.filter, ref match) && this.body.PerformMatch(o.body, ref match) && variable == o.variable;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Try-finally statement
public sealed partial class TryFinally : TryInstruction
{
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitTryFinally(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitTryFinally(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitTryFinally(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as TryFinally;
return o != null && TryBlock.PerformMatch(o.TryBlock, ref match) && finallyBlock.PerformMatch(o.finallyBlock, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Try-fault statement
public sealed partial class TryFault : TryInstruction
{
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitTryFault(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitTryFault(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitTryFault(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as TryFault;
return o != null && TryBlock.PerformMatch(o.TryBlock, ref match) && faultBlock.PerformMatch(o.faultBlock, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Breakpoint instruction
public sealed partial class DebugBreak : SimpleInstruction
{
public DebugBreak() : base(OpCode.DebugBreak)
{
}
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.SideEffect;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.SideEffect;
}
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitDebugBreak(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitDebugBreak(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitDebugBreak(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as DebugBreak;
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Comparison. The inputs must be both integers; or both floats; or both object references. Object references can only be compared for equality or inequality. Floating-point comparisons evaluate to 0 (false) when an input is NaN, except for 'NaN != NaN' which evaluates to 1 (true).
public sealed partial class Comp : BinaryInstruction
{
public override StackType ResultType { get { return StackType.I4; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitComp(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitComp(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitComp(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Comp;
return o != null && this.Left.PerformMatch(o.Left, ref match) && this.Right.PerformMatch(o.Right, ref match) && this.Kind == o.Kind && this.Sign == o.Sign;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Non-virtual method call.
public sealed partial class Call : CallInstruction
{
public Call(IMethod method) : base(OpCode.Call, method)
{
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitCall(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitCall(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitCall(this, context);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Virtual method call.
public sealed partial class CallVirt : CallInstruction
{
public CallVirt(IMethod method) : base(OpCode.CallVirt, method)
{
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitCallVirt(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitCallVirt(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitCallVirt(this, context);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Checks that the input float is not NaN or infinite.
public sealed partial class Ckfinite : UnaryInstruction
{
public Ckfinite(ILInstruction argument) : base(OpCode.Ckfinite, argument)
{
}
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayThrow;
}
public override InstructionFlags DirectFlags {
get {
return base.DirectFlags | InstructionFlags.MayThrow;
}
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitCkfinite(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitCkfinite(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitCkfinite(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Ckfinite;
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Numeric cast.
public sealed partial class Conv : UnaryInstruction
{
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitConv(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitConv(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitConv(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Conv;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && CheckForOverflow == o.CheckForOverflow && Kind == o.Kind && InputSign == o.InputSign && TargetType == o.TargetType;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Loads the value of a local variable. (ldarg/ldloc)
public sealed partial class LdLoc : SimpleInstruction, ILoadInstruction
{
public LdLoc(ILVariable variable) : base(OpCode.LdLoc)
{
Debug.Assert(variable != null);
this.variable = variable;
}
ILVariable variable;
public ILVariable Variable {
get { return variable; }
set {
Debug.Assert(value != null);
if (IsConnected)
variable.RemoveLoadInstruction(this);
variable = value;
if (IsConnected)
variable.AddLoadInstruction(this);
}
}
public int IndexInLoadInstructionList { get; set; } = -1;
int IInstructionWithVariableOperand.IndexInVariableInstructionMapping {
get { return ((ILoadInstruction)this).IndexInLoadInstructionList; }
set { ((ILoadInstruction)this).IndexInLoadInstructionList = value; }
}
protected override void Connected()
{
base.Connected();
variable.AddLoadInstruction(this);
}
protected override void Disconnected()
{
variable.RemoveLoadInstruction(this);
base.Disconnected();
}
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function));
}
public override StackType ResultType { get { return variable.StackType; } }
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayReadLocals;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayReadLocals;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
variable.WriteTo(output);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdLoc(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdLoc(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdLoc(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdLoc;
return o != null && variable == o.variable;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Loads the address of a local variable. (ldarga/ldloca)
public sealed partial class LdLoca : SimpleInstruction, IAddressInstruction
{
public LdLoca(ILVariable variable) : base(OpCode.LdLoca)
{
Debug.Assert(variable != null);
this.variable = variable;
}
public override StackType ResultType { get { return StackType.Ref; } }
ILVariable variable;
public ILVariable Variable {
get { return variable; }
set {
Debug.Assert(value != null);
if (IsConnected)
variable.RemoveAddressInstruction(this);
variable = value;
if (IsConnected)
variable.AddAddressInstruction(this);
}
}
public int IndexInAddressInstructionList { get; set; } = -1;
int IInstructionWithVariableOperand.IndexInVariableInstructionMapping {
get { return ((IAddressInstruction)this).IndexInAddressInstructionList; }
set { ((IAddressInstruction)this).IndexInAddressInstructionList = value; }
}
protected override void Connected()
{
base.Connected();
variable.AddAddressInstruction(this);
}
protected override void Disconnected()
{
variable.RemoveAddressInstruction(this);
base.Disconnected();
}
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function));
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
variable.WriteTo(output);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdLoca(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdLoca(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdLoca(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdLoca;
return o != null && variable == o.variable;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Stores a value into a local variable. (starg/stloc)
public sealed partial class StLoc : ILInstruction, IStoreInstruction
{
public StLoc(ILVariable variable, ILInstruction value) : base(OpCode.StLoc)
{
Debug.Assert(variable != null);
this.variable = variable;
this.Value = value;
}
ILVariable variable;
public ILVariable Variable {
get { return variable; }
set {
Debug.Assert(value != null);
if (IsConnected)
variable.RemoveStoreInstruction(this);
variable = value;
if (IsConnected)
variable.AddStoreInstruction(this);
}
}
public int IndexInStoreInstructionList { get; set; } = -1;
int IInstructionWithVariableOperand.IndexInVariableInstructionMapping {
get { return ((IStoreInstruction)this).IndexInStoreInstructionList; }
set { ((IStoreInstruction)this).IndexInStoreInstructionList = value; }
}
protected override void Connected()
{
base.Connected();
variable.AddStoreInstruction(this);
}
protected override void Disconnected()
{
variable.RemoveStoreInstruction(this);
base.Disconnected();
}
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function));
}
public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true);
ILInstruction value;
public ILInstruction Value {
get { return this.value; }
set {
ValidateChild(value);
SetChildInstruction(ref this.value, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.value;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Value = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return ValueSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (StLoc)ShallowClone();
clone.Value = this.value.Clone();
return clone;
}
public override StackType ResultType { get { return variable.StackType; } }
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayWriteLocals | value.Flags;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayWriteLocals;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
variable.WriteTo(output);
output.Write('(');
this.value.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitStLoc(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitStLoc(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitStLoc(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as StLoc;
return o != null && variable == o.variable && this.value.PerformMatch(o.value, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Stores the value into an anonymous temporary variable, and returns the address of that variable.
public sealed partial class AddressOf : ILInstruction
{
public AddressOf(ILInstruction value) : base(OpCode.AddressOf)
{
this.Value = value;
}
public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true);
ILInstruction value;
public ILInstruction Value {
get { return this.value; }
set {
ValidateChild(value);
SetChildInstruction(ref this.value, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.value;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Value = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return ValueSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (AddressOf)ShallowClone();
clone.Value = this.value.Clone();
return clone;
}
public override StackType ResultType { get { return StackType.Ref; } }
protected override InstructionFlags ComputeFlags()
{
return value.Flags;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.None;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write('(');
this.value.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitAddressOf(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitAddressOf(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitAddressOf(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as AddressOf;
return o != null && this.value.PerformMatch(o.value, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Loads a constant string.
public sealed partial class LdStr : SimpleInstruction
{
public LdStr(string value) : base(OpCode.LdStr)
{
this.Value = value;
}
public readonly string Value;
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdStr(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdStr(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdStr(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdStr;
return o != null && this.Value == o.Value;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Loads a constant 32-bit integer.
public sealed partial class LdcI4 : SimpleInstruction
{
public LdcI4(int value) : base(OpCode.LdcI4)
{
this.Value = value;
}
public readonly int Value;
public override StackType ResultType { get { return StackType.I4; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdcI4(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdcI4(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdcI4(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdcI4;
return o != null && this.Value == o.Value;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Loads a constant 64-bit integer.
public sealed partial class LdcI8 : SimpleInstruction
{
public LdcI8(long value) : base(OpCode.LdcI8)
{
this.Value = value;
}
public readonly long Value;
public override StackType ResultType { get { return StackType.I8; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdcI8(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdcI8(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdcI8(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdcI8;
return o != null && this.Value == o.Value;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Loads a constant floating-point number.
public sealed partial class LdcF : SimpleInstruction
{
public LdcF(double value) : base(OpCode.LdcF)
{
this.Value = value;
}
public readonly double Value;
public override StackType ResultType { get { return StackType.F; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdcF(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdcF(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdcF(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdcF;
return o != null && this.Value == o.Value;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Loads a constant decimal.
public sealed partial class LdcDecimal : SimpleInstruction
{
public LdcDecimal(decimal value) : base(OpCode.LdcDecimal)
{
this.Value = value;
}
public readonly decimal Value;
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdcDecimal(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdcDecimal(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdcDecimal(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdcDecimal;
return o != null && this.Value == o.Value;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Loads the null reference.
public sealed partial class LdNull : SimpleInstruction
{
public LdNull() : base(OpCode.LdNull)
{
}
public override StackType ResultType { get { return StackType.O; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdNull(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdNull(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdNull(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdNull;
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Load method pointer
public sealed partial class LdFtn : SimpleInstruction, IInstructionWithMethodOperand
{
public LdFtn(IMethod method) : base(OpCode.LdFtn)
{
this.method = method;
}
readonly IMethod method;
/// Returns the method operand.
public IMethod Method { get { return method; } }
public override StackType ResultType { get { return StackType.I; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, method);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdFtn(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdFtn(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdFtn(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdFtn;
return o != null && method.Equals(o.method);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Load method pointer
public sealed partial class LdVirtFtn : UnaryInstruction, IInstructionWithMethodOperand
{
public LdVirtFtn(ILInstruction argument, IMethod method) : base(OpCode.LdVirtFtn, argument)
{
this.method = method;
}
readonly IMethod method;
/// Returns the method operand.
public IMethod Method { get { return method; } }
public override StackType ResultType { get { return StackType.I; } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayThrow;
}
public override InstructionFlags DirectFlags {
get {
return base.DirectFlags | InstructionFlags.MayThrow;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, method);
output.Write('(');
Argument.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdVirtFtn(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdVirtFtn(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdVirtFtn(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdVirtFtn;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && method.Equals(o.method);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Loads runtime representation of metadata token
public sealed partial class LdTypeToken : SimpleInstruction
{
public LdTypeToken(IType type) : base(OpCode.LdTypeToken)
{
this.type = type;
}
readonly IType type;
/// Returns the type operand.
public IType Type { get { return type; } }
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdTypeToken(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdTypeToken(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdTypeToken(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdTypeToken;
return o != null && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Loads runtime representation of metadata token
public sealed partial class LdMemberToken : SimpleInstruction
{
public LdMemberToken(IMember member) : base(OpCode.LdMemberToken)
{
this.member = member;
}
readonly IMember member;
/// Returns the token operand.
public IMember Member { get { return member; } }
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, member);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdMemberToken(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdMemberToken(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdMemberToken(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdMemberToken;
return o != null && member.Equals(o.member);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Allocates space in the stack frame
public sealed partial class LocAlloc : UnaryInstruction
{
public LocAlloc(ILInstruction argument) : base(OpCode.LocAlloc, argument)
{
}
public override StackType ResultType { get { return StackType.I; } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayThrow;
}
public override InstructionFlags DirectFlags {
get {
return base.DirectFlags | InstructionFlags.MayThrow;
}
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLocAlloc(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLocAlloc(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLocAlloc(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LocAlloc;
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Returns from the current method or lambda. Only used when returning a value; void returns are represented using a 'leave' instruction.
public sealed partial class Return : ILInstruction
{
public Return(ILInstruction value) : base(OpCode.Return)
{
this.Value = value;
}
public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true);
ILInstruction value;
public ILInstruction Value {
get { return this.value; }
set {
ValidateChild(value);
SetChildInstruction(ref this.value, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.value;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Value = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return ValueSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (Return)ShallowClone();
clone.Value = this.value.Clone();
return clone;
}
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags()
{
return value.Flags | InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write('(');
this.value.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitReturn(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitReturn(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitReturn(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Return;
return o != null && this.value.PerformMatch(o.value, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Load address of instance field
public sealed partial class LdFlda : ILInstruction, IInstructionWithFieldOperand
{
public LdFlda(ILInstruction target, IField field) : base(OpCode.LdFlda)
{
this.Target = target;
this.field = field;
}
public static readonly SlotInfo TargetSlot = new SlotInfo("Target", canInlineInto: true);
ILInstruction target;
public ILInstruction Target {
get { return this.target; }
set {
ValidateChild(value);
SetChildInstruction(ref this.target, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.target;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Target = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return TargetSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (LdFlda)ShallowClone();
clone.Target = this.target.Clone();
return clone;
}
public bool DelayExceptions; // NullReferenceException/IndexOutOfBoundsException only occurs when the reference is dereferenced
readonly IField field;
/// Returns the field operand.
public IField Field { get { return field; } }
public override StackType ResultType { get { return StackType.Ref; } }
protected override InstructionFlags ComputeFlags()
{
return target.Flags | (DelayExceptions ? InstructionFlags.None : InstructionFlags.MayThrow);
}
public override InstructionFlags DirectFlags {
get {
return (DelayExceptions ? InstructionFlags.None : InstructionFlags.MayThrow);
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
output.Write('(');
this.target.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdFlda(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdFlda(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdFlda(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdFlda;
return o != null && this.target.PerformMatch(o.target, ref match) && field.Equals(o.field);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Load static field address
public sealed partial class LdsFlda : SimpleInstruction, IInstructionWithFieldOperand
{
public LdsFlda(IField field) : base(OpCode.LdsFlda)
{
this.field = field;
}
public override StackType ResultType { get { return StackType.Ref; } }
readonly IField field;
/// Returns the field operand.
public IField Field { get { return field; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdsFlda(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdsFlda(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdsFlda(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdsFlda;
return o != null && field.Equals(o.field);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Casts an object to a class.
public sealed partial class CastClass : UnaryInstruction
{
public CastClass(ILInstruction argument, IType type) : base(OpCode.CastClass, argument)
{
this.type = type;
}
readonly IType type;
/// Returns the type operand.
public IType Type { get { return type; } }
public override StackType ResultType { get { return type.GetStackType(); } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayThrow;
}
public override InstructionFlags DirectFlags {
get {
return base.DirectFlags | InstructionFlags.MayThrow;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('(');
Argument.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitCastClass(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitCastClass(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitCastClass(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as CastClass;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Test if object is instance of class or interface.
public sealed partial class IsInst : UnaryInstruction
{
public IsInst(ILInstruction argument, IType type) : base(OpCode.IsInst, argument)
{
this.type = type;
}
readonly IType type;
/// Returns the type operand.
public IType Type { get { return type; } }
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('(');
Argument.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitIsInst(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitIsInst(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitIsInst(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as IsInst;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Indirect load (ref/pointer dereference).
public sealed partial class LdObj : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{
public LdObj(ILInstruction target, IType type) : base(OpCode.LdObj)
{
this.Target = target;
this.type = type;
}
public static readonly SlotInfo TargetSlot = new SlotInfo("Target", canInlineInto: true);
ILInstruction target;
public ILInstruction Target {
get { return this.target; }
set {
ValidateChild(value);
SetChildInstruction(ref this.target, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.target;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Target = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return TargetSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (LdObj)ShallowClone();
clone.Target = this.target.Clone();
return clone;
}
readonly IType type;
/// Returns the type operand.
public IType Type { get { return type; } }
/// Gets/Sets whether the memory access is volatile.
public bool IsVolatile { get; set; }
/// Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.
public byte UnalignedPrefix { get; set; }
public override StackType ResultType { get { return type.GetStackType(); } }
protected override InstructionFlags ComputeFlags()
{
return target.Flags | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
}
public override void WriteTo(ITextOutput output)
{
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix > 0)
output.Write("unaligned(" + UnalignedPrefix + ").");
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('(');
this.target.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdObj(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdObj(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdObj(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdObj;
return o != null && this.target.PerformMatch(o.target, ref match) && type.Equals(o.type) && IsVolatile == o.IsVolatile && UnalignedPrefix == o.UnalignedPrefix;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Indirect store (store to ref/pointer).
public sealed partial class StObj : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{
public StObj(ILInstruction target, ILInstruction value, IType type) : base(OpCode.StObj)
{
this.Target = target;
this.Value = value;
this.type = type;
}
public static readonly SlotInfo TargetSlot = new SlotInfo("Target", canInlineInto: true);
ILInstruction target;
public ILInstruction Target {
get { return this.target; }
set {
ValidateChild(value);
SetChildInstruction(ref this.target, value, 0);
}
}
public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true);
ILInstruction value;
public ILInstruction Value {
get { return this.value; }
set {
ValidateChild(value);
SetChildInstruction(ref this.value, value, 1);
}
}
protected sealed override int GetChildCount()
{
return 2;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.target;
case 1:
return this.value;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Target = value;
break;
case 1:
this.Value = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return TargetSlot;
case 1:
return ValueSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (StObj)ShallowClone();
clone.Target = this.target.Clone();
clone.Value = this.value.Clone();
return clone;
}
readonly IType type;
/// Returns the type operand.
public IType Type { get { return type; } }
/// Gets/Sets whether the memory access is volatile.
public bool IsVolatile { get; set; }
/// Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.
public byte UnalignedPrefix { get; set; }
public override StackType ResultType { get { return type.GetStackType(); } }
protected override InstructionFlags ComputeFlags()
{
return target.Flags | value.Flags | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
}
public override void WriteTo(ITextOutput output)
{
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix > 0)
output.Write("unaligned(" + UnalignedPrefix + ").");
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('(');
this.target.WriteTo(output);
output.Write(", ");
this.value.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitStObj(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitStObj(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitStObj(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as StObj;
return o != null && this.target.PerformMatch(o.target, ref match) && this.value.PerformMatch(o.value, ref match) && type.Equals(o.type) && IsVolatile == o.IsVolatile && UnalignedPrefix == o.UnalignedPrefix;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Boxes a value.
public sealed partial class Box : UnaryInstruction
{
public Box(ILInstruction argument, IType type) : base(OpCode.Box, argument)
{
this.type = type;
}
readonly IType type;
/// Returns the type operand.
public IType Type { get { return type; } }
public override StackType ResultType { get { return StackType.O; } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
public override InstructionFlags DirectFlags {
get {
return base.DirectFlags | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('(');
Argument.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitBox(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitBox(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitBox(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Box;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Compute address inside box.
public sealed partial class Unbox : UnaryInstruction
{
public Unbox(ILInstruction argument, IType type) : base(OpCode.Unbox, argument)
{
this.type = type;
}
readonly IType type;
/// Returns the type operand.
public IType Type { get { return type; } }
public override StackType ResultType { get { return StackType.Ref; } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayThrow;
}
public override InstructionFlags DirectFlags {
get {
return base.DirectFlags | InstructionFlags.MayThrow;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('(');
Argument.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitUnbox(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitUnbox(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitUnbox(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Unbox;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Unbox a value.
public sealed partial class UnboxAny : UnaryInstruction
{
public UnboxAny(ILInstruction argument, IType type) : base(OpCode.UnboxAny, argument)
{
this.type = type;
}
readonly IType type;
/// Returns the type operand.
public IType Type { get { return type; } }
public override StackType ResultType { get { return type.GetStackType(); } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
public override InstructionFlags DirectFlags {
get {
return base.DirectFlags | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('(');
Argument.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitUnboxAny(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitUnboxAny(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitUnboxAny(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as UnboxAny;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Creates an object instance and calls the constructor.
public sealed partial class NewObj : CallInstruction
{
public NewObj(IMethod method) : base(OpCode.NewObj, method)
{
}
public override StackType ResultType { get { return Method.DeclaringType.GetStackType(); } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitNewObj(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitNewObj(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitNewObj(this, context);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Creates an array instance.
public sealed partial class NewArr : ILInstruction
{
public NewArr(IType type, params ILInstruction[] indices) : base(OpCode.NewArr)
{
this.type = type;
this.Indices = new InstructionCollection(this, 0);
this.Indices.AddRange(indices);
}
readonly IType type;
/// Returns the type operand.
public IType Type { get { return type; } }
public static readonly SlotInfo IndicesSlot = new SlotInfo("Indices", canInlineInto: true);
public InstructionCollection Indices { get; private set; }
protected sealed override int GetChildCount()
{
return Indices.Count;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
default:
return this.Indices[index - 0];
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
default:
this.Indices[index - 0] = value;
break;
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
default:
return IndicesSlot;
}
}
public sealed override ILInstruction Clone()
{
var clone = (NewArr)ShallowClone();
clone.Indices = new InstructionCollection(clone, 0);
clone.Indices.AddRange(this.Indices.Select(arg => arg.Clone()));
return clone;
}
public override StackType ResultType { get { return StackType.O; } }
protected override InstructionFlags ComputeFlags()
{
return Indices.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags) | InstructionFlags.MayThrow;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayThrow;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('(');
bool first = true;
foreach (var indices in Indices) {
if (!first) output.Write(", "); else first = false;
indices.WriteTo(output);
}
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitNewArr(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitNewArr(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitNewArr(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as NewArr;
return o != null && type.Equals(o.type) && Patterns.ListMatch.DoMatch(this.Indices, o.Indices, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Returns the default value for a type.
public sealed partial class DefaultValue : SimpleInstruction
{
public DefaultValue(IType type) : base(OpCode.DefaultValue)
{
this.type = type;
}
readonly IType type;
/// Returns the type operand.
public IType Type { get { return type; } }
public override StackType ResultType { get { return type.GetStackType(); } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitDefaultValue(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitDefaultValue(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitDefaultValue(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as DefaultValue;
return o != null && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Throws an exception.
public sealed partial class Throw : UnaryInstruction
{
public Throw(ILInstruction argument) : base(OpCode.Throw, argument)
{
}
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable;
}
public override InstructionFlags DirectFlags {
get {
return base.DirectFlags | InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable;
}
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitThrow(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitThrow(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitThrow(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Throw;
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Rethrows the current exception.
public sealed partial class Rethrow : SimpleInstruction
{
public Rethrow() : base(OpCode.Rethrow)
{
}
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable;
}
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitRethrow(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitRethrow(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitRethrow(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Rethrow;
return o != null;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Gets the size of a type in bytes.
public sealed partial class SizeOf : SimpleInstruction
{
public SizeOf(IType type) : base(OpCode.SizeOf)
{
this.type = type;
}
readonly IType type;
/// Returns the type operand.
public IType Type { get { return type; } }
public override StackType ResultType { get { return StackType.I4; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitSizeOf(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitSizeOf(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitSizeOf(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as SizeOf;
return o != null && type.Equals(o.type);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Returns the length of an array as 'native unsigned int'.
public sealed partial class LdLen : ILInstruction
{
public static readonly SlotInfo ArraySlot = new SlotInfo("Array", canInlineInto: true);
ILInstruction array;
public ILInstruction Array {
get { return this.array; }
set {
ValidateChild(value);
SetChildInstruction(ref this.array, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.array;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Array = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return ArraySlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (LdLen)ShallowClone();
clone.Array = this.array.Clone();
return clone;
}
protected override InstructionFlags ComputeFlags()
{
return array.Flags | InstructionFlags.MayThrow;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayThrow;
}
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdLen(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdLen(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdLen(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdLen;
return o != null && this.array.PerformMatch(o.array, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Load address of array element.
public sealed partial class LdElema : ILInstruction
{
public LdElema(IType type, ILInstruction array, params ILInstruction[] indices) : base(OpCode.LdElema)
{
this.type = type;
this.Array = array;
this.Indices = new InstructionCollection(this, 1);
this.Indices.AddRange(indices);
}
readonly IType type;
/// Returns the type operand.
public IType Type { get { return type; } }
public static readonly SlotInfo ArraySlot = new SlotInfo("Array", canInlineInto: true);
ILInstruction array;
public ILInstruction Array {
get { return this.array; }
set {
ValidateChild(value);
SetChildInstruction(ref this.array, value, 0);
}
}
public static readonly SlotInfo IndicesSlot = new SlotInfo("Indices", canInlineInto: true);
public InstructionCollection Indices { get; private set; }
protected sealed override int GetChildCount()
{
return 1 + Indices.Count;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.array;
default:
return this.Indices[index - 1];
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Array = value;
break;
default:
this.Indices[index - 1] = value;
break;
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return ArraySlot;
default:
return IndicesSlot;
}
}
public sealed override ILInstruction Clone()
{
var clone = (LdElema)ShallowClone();
clone.Array = this.array.Clone();
clone.Indices = new InstructionCollection(clone, 1);
clone.Indices.AddRange(this.Indices.Select(arg => arg.Clone()));
return clone;
}
public bool DelayExceptions; // NullReferenceException/IndexOutOfBoundsException only occurs when the reference is dereferenced
public override StackType ResultType { get { return StackType.Ref; } }
/// Gets whether the 'readonly' prefix was applied to this instruction.
public bool IsReadOnly { get; set; }
protected override InstructionFlags ComputeFlags()
{
return array.Flags | Indices.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags) | (DelayExceptions ? InstructionFlags.None : InstructionFlags.MayThrow);
}
public override InstructionFlags DirectFlags {
get {
return (DelayExceptions ? InstructionFlags.None : InstructionFlags.MayThrow);
}
}
public override void WriteTo(ITextOutput output)
{
if (IsReadOnly)
output.Write("readonly.");
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('(');
this.array.WriteTo(output);
foreach (var indices in Indices) {
output.Write(", ");
indices.WriteTo(output);
}
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdElema(this);
}
public override T AcceptVisitor(ILVisitor visitor)
{
return visitor.VisitLdElema(this);
}
public override T AcceptVisitor(ILVisitor visitor, C context)
{
return visitor.VisitLdElema(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as LdElema;
return o != null && type.Equals(o.type) && this.array.PerformMatch(o.array, ref match) && Patterns.ListMatch.DoMatch(this.Indices, o.Indices, ref match) && IsReadOnly == o.IsReadOnly;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// Converts an array pointer (O) to a reference to the first element, or to a null reference if the array is null or empty.
/// Also used to convert a string to a reference to the first character.
public sealed partial class ArrayToPointer : ILInstruction
{
public ArrayToPointer(ILInstruction array) : base(OpCode.ArrayToPointer)
{
this.Array = array;
}
public static readonly SlotInfo ArraySlot = new SlotInfo("Array", canInlineInto: true);
ILInstruction array;
public ILInstruction Array {
get { return this.array; }
set {
ValidateChild(value);
SetChildInstruction(ref this.array, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.array;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Array = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return ArraySlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (ArrayToPointer)ShallowClone();
clone.Array = this.array.Clone();
return clone;
}
public override StackType ResultType { get { return StackType.Ref; } }
protected override InstructionFlags ComputeFlags()
{
return array.Flags;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.None;
}
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write('(');
this.array.WriteTo(output);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitArrayToPointer(this);
}
public override T AcceptVisitor(ILVisitor