// 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 Mono.Cecil;
namespace ICSharpCode.Decompiler.IL
{
	/// 
	/// Enum representing the type of an .
	/// 
	public enum OpCode
	{
		/// No operation. Takes 0 arguments and returns void.
		Nop,
		/// Pops the top of the evaluation stack and returns the value.
		Pop,
		/// Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'.
		Peek,
		/// Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.
		Void,
		/// A container of IL blocks.
		ILFunction,
		/// A container of IL blocks.
		BlockContainer,
		/// A block of IL instructions.
		Block,
		/// Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).
		LogicNot,
		/// Adds two numbers.
		Add,
		/// Subtracts two numbers
		Sub,
		/// Multiplies two numbers
		Mul,
		/// Divides two numbers
		Div,
		/// Division remainder
		Rem,
		/// Bitwise AND
		BitAnd,
		/// Bitwise OR
		BitOr,
		/// Bitwise XOR
		BitXor,
		/// Bitwise NOT
		BitNot,
		/// Retrieves the RuntimeArgumentHandle.
		Arglist,
		/// Unconditional branch. goto target;
		Branch,
		/// Marks the end of an finally, fault or exception filter block.
		EndFinally,
		/// If statement / conditional expression. if (condition) trueExpr else falseExpr
		IfInstruction,
		/// Try-catch statement
		TryCatch,
		/// Catch handler within a try-catch statement
		TryCatchHandler,
		/// Try-finally statement
		TryFinally,
		/// Try-fault statement
		TryFault,
		/// Breakpoint instruction
		DebugBreak,
		/// Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.
		Ceq,
		/// Compare greater than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.
		Cgt,
		/// Compare greater than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.
		Cgt_Un,
		/// Compare less than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.
		Clt,
		/// Compare less than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.
		Clt_Un,
		/// Non-virtual method call.
		Call,
		/// Virtual method call.
		CallVirt,
		/// Checks that the float on top of the stack is not NaN or infinite.
		Ckfinite,
		/// Numeric cast.
		Conv,
		/// Loads the value of a local variable. (ldarg/ldloc)
		LdLoc,
		/// Loads the address of a local variable. (ldarga/ldloca)
		LdLoca,
		/// Stores a value into a local variable. (starg/stloc)
		StLoc,
		/// Loads a constant string.
		LdStr,
		/// Loads a constant 32-bit integer.
		LdcI4,
		/// Loads a constant 64-bit integer.
		LdcI8,
		/// Loads a constant floating-point number.
		LdcF,
		/// Loads the null reference.
		LdNull,
		/// Load method pointer
		LdFtn,
		/// Load method pointer
		LdVirtFtn,
		/// Loads runtime representation of metadata token
		LdToken,
		/// Allocates space in the stack frame
		LocAlloc,
		/// Returns from the current method or lambda.
		Return,
		/// Shift left
		Shl,
		/// Shift right
		Shr,
		/// Load instance field
		LdFld,
		/// Load address of instance field
		LdFlda,
		/// Store value to instance field
		StFld,
		/// Load static field
		LdsFld,
		/// Load static field address
		LdsFlda,
		/// Store value to static field
		StsFld,
		/// 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,
		/// Initializes the value at an address.
		InitObj,
		/// 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,
	}
	/// Instruction with a single argument
	public abstract partial class UnaryInstruction : ILInstruction
	{
		protected UnaryInstruction(OpCode opCode, ILInstruction argument) : base(opCode)
		{
			this.Argument = argument;
		}
		ILInstruction argument;
		public ILInstruction Argument {
			get { return this.argument; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.argument, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.argument;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Argument = this.argument.AcceptVisitor(visitor);
		}
		internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack instructionStack, out bool finished)
		{
			this.Argument = this.argument.Inline(flagsBefore, instructionStack, out finished);
			return this;
		}
		protected override InstructionFlags ComputeFlags()
		{
			return argument.Flags;
		}
		public override void WriteTo(ITextOutput output)
		{
			output.Write(OpCode);
			output.Write('(');
			this.argument.WriteTo(output);
			output.Write(')');
		}
	}
	/// 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;
		}
		ILInstruction left;
		public ILInstruction Left {
			get { return this.left; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.left, value);
			}
		}
		ILInstruction right;
		public ILInstruction Right {
			get { return this.right; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.right, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.left;
				yield return this.right;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Left = this.left.AcceptVisitor(visitor);
			this.Right = this.right.AcceptVisitor(visitor);
		}
		internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack instructionStack, out bool finished)
		{
			this.Right = this.right.Inline(flagsBefore | ((this.left.Flags) & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop)), instructionStack, out finished);
			if (finished)
				this.Left = this.left.Inline(flagsBefore, instructionStack, out finished);
			return this;
		}
		protected override InstructionFlags ComputeFlags()
		{
			return left.Flags | right.Flags;
		}
		public override void WriteTo(ITextOutput output)
		{
			output.Write(OpCode);
			output.Write('(');
			this.left.WriteTo(output);
			output.Write(", ");
			this.right.WriteTo(output);
			output.Write(')');
		}
	}
	/// 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitNop(this);
		}
	}
	/// Pops the top of the evaluation stack and returns the value.
	public sealed partial class Pop : SimpleInstruction
	{
		public Pop(StackType resultType) : base(OpCode.Pop)
		{
			this.resultType = resultType;
		}
		StackType resultType;
		public override StackType ResultType { get { return resultType; } }
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitPop(this);
		}
	}
	/// Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'.
	public sealed partial class Peek : SimpleInstruction
	{
		public Peek(StackType resultType) : base(OpCode.Peek)
		{
			this.resultType = resultType;
		}
		StackType resultType;
		public override StackType ResultType { get { return resultType; } }
		protected override InstructionFlags ComputeFlags()
		{
			return InstructionFlags.MayPeek;
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitPeek(this);
		}
	}
	/// Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.
	public sealed partial class Void : UnaryInstruction
	{
		public Void(ILInstruction argument) : base(OpCode.Void, argument)
		{
		}
		public override StackType ResultType { get { return StackType.Void; } }
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitVoid(this);
		}
	}
	/// A container of IL blocks.
	public sealed partial class ILFunction : ILInstruction
	{
		ILInstruction body;
		public ILInstruction Body {
			get { return this.body; }
			set {
				ValidateChild(value);
				SetChildInstruction(ref this.body, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.body;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Body = this.body.AcceptVisitor(visitor);
		}
		public override StackType ResultType { get { return StackType.O; } }
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitILFunction(this);
		}
	}
	/// A container of IL blocks.
	public sealed partial class BlockContainer : ILInstruction
	{
		public override StackType ResultType { get { return StackType.Void; } }
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitBlockContainer(this);
		}
	}
	/// A block of IL instructions.
	public sealed partial class Block : ILInstruction
	{
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitBlock(this);
		}
	}
	/// Unary operator that expects an input of type I4. Returns 1 (of type I4) if the input value is 0. Otherwise, returns 0 (of type I4).
	public sealed partial class LogicNot : UnaryInstruction
	{
		public LogicNot(ILInstruction argument) : base(OpCode.LogicNot, argument)
		{
		}
		public override StackType ResultType { get { return StackType.I4; } }
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLogicNot(this);
		}
	}
	/// Adds two numbers.
	public sealed partial class Add : BinaryNumericInstruction
	{
		public Add(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Add, left, right, checkForOverflow, sign)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitAdd(this);
		}
	}
	/// Subtracts two numbers
	public sealed partial class Sub : BinaryNumericInstruction
	{
		public Sub(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Sub, left, right, checkForOverflow, sign)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitSub(this);
		}
	}
	/// Multiplies two numbers
	public sealed partial class Mul : BinaryNumericInstruction
	{
		public Mul(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Mul, left, right, checkForOverflow, sign)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitMul(this);
		}
	}
	/// Divides two numbers
	public sealed partial class Div : BinaryNumericInstruction
	{
		public Div(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Div, left, right, checkForOverflow, sign)
		{
		}
		protected override InstructionFlags ComputeFlags()
		{
			return base.ComputeFlags() | InstructionFlags.MayThrow;
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitDiv(this);
		}
	}
	/// Division remainder
	public sealed partial class Rem : BinaryNumericInstruction
	{
		public Rem(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Rem, left, right, checkForOverflow, sign)
		{
		}
		protected override InstructionFlags ComputeFlags()
		{
			return base.ComputeFlags() | InstructionFlags.MayThrow;
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitRem(this);
		}
	}
	/// Bitwise AND
	public sealed partial class BitAnd : BinaryNumericInstruction
	{
		public BitAnd(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.BitAnd, left, right, checkForOverflow, sign)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitBitAnd(this);
		}
	}
	/// Bitwise OR
	public sealed partial class BitOr : BinaryNumericInstruction
	{
		public BitOr(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.BitOr, left, right, checkForOverflow, sign)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitBitOr(this);
		}
	}
	/// Bitwise XOR
	public sealed partial class BitXor : BinaryNumericInstruction
	{
		public BitXor(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.BitXor, left, right, checkForOverflow, sign)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitBitXor(this);
		}
	}
	/// Bitwise NOT
	public sealed partial class BitNot : UnaryInstruction
	{
		public BitNot(ILInstruction argument) : base(OpCode.BitNot, argument)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitBitNot(this);
		}
	}
	/// Retrieves the RuntimeArgumentHandle.
	public sealed partial class Arglist : SimpleInstruction
	{
		public Arglist() : base(OpCode.Arglist)
		{
		}
		public override StackType ResultType { get { return StackType.O; } }
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitArglist(this);
		}
	}
	/// Unconditional branch. goto target;
	public sealed partial class Branch : SimpleInstruction
	{
		public override StackType ResultType { get { return StackType.Void; } }
		protected override InstructionFlags ComputeFlags()
		{
			return InstructionFlags.EndPointUnreachable | InstructionFlags.MayBranch;
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitBranch(this);
		}
	}
	/// Marks the end of an finally, fault or exception filter block.
	public sealed partial class EndFinally : SimpleInstruction
	{
		public EndFinally() : base(OpCode.EndFinally)
		{
		}
		public override StackType ResultType { get { return StackType.Void; } }
		protected override InstructionFlags ComputeFlags()
		{
			return InstructionFlags.EndPointUnreachable | InstructionFlags.MayBranch;
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitEndFinally(this);
		}
	}
	/// If statement / conditional expression. if (condition) trueExpr else falseExpr
	public sealed partial class IfInstruction : ILInstruction
	{
		ILInstruction condition;
		public ILInstruction Condition {
			get { return this.condition; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.condition, value);
			}
		}
		ILInstruction trueInst;
		public ILInstruction TrueInst {
			get { return this.trueInst; }
			set {
				ValidateChild(value);
				SetChildInstruction(ref this.trueInst, value);
			}
		}
		ILInstruction falseInst;
		public ILInstruction FalseInst {
			get { return this.falseInst; }
			set {
				ValidateChild(value);
				SetChildInstruction(ref this.falseInst, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.condition;
				yield return this.trueInst;
				yield return this.falseInst;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Condition = this.condition.AcceptVisitor(visitor);
			this.TrueInst = this.trueInst.AcceptVisitor(visitor);
			this.FalseInst = this.falseInst.AcceptVisitor(visitor);
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitIfInstruction(this);
		}
	}
	/// Try-catch statement
	public sealed partial class TryCatch : TryInstruction
	{
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitTryCatch(this);
		}
	}
	/// Catch handler within a try-catch statement
	public sealed partial class TryCatchHandler : ILInstruction
	{
		public TryCatchHandler(ILInstruction filter, ILInstruction body, ILVariable variable) : base(OpCode.TryCatchHandler)
		{
			this.Filter = filter;
			this.Body = body;
			Debug.Assert(variable != null);
			this.variable = variable;
		}
		ILInstruction filter;
		public ILInstruction Filter {
			get { return this.filter; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.filter, value);
			}
		}
		ILInstruction body;
		public ILInstruction Body {
			get { return this.body; }
			set {
				ValidateChild(value);
				SetChildInstruction(ref this.body, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.filter;
				yield return this.body;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Filter = this.filter.AcceptVisitor(visitor);
			this.Body = this.body.AcceptVisitor(visitor);
		}
		readonly ILVariable variable;
		/// Returns the variable operand.
		public ILVariable Variable { get { return variable; } }
		public override StackType ResultType { get { return StackType.Void; } }
		protected override InstructionFlags ComputeFlags()
		{
			return filter.Flags | body.Flags;
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitTryCatchHandler(this);
		}
	}
	/// Try-finally statement
	public sealed partial class TryFinally : TryInstruction
	{
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitTryFinally(this);
		}
	}
	/// Try-fault statement
	public sealed partial class TryFault : TryInstruction
	{
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitTryFault(this);
		}
	}
	/// 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitDebugBreak(this);
		}
	}
	/// Compare equal. Returns 1 (of type I4) if two numbers or object references are equal; 0 otherwise.
	public sealed partial class Ceq : BinaryComparisonInstruction
	{
		public Ceq(ILInstruction left, ILInstruction right) : base(OpCode.Ceq, left, right)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitCeq(this);
		}
	}
	/// Compare greater than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.
	public sealed partial class Cgt : BinaryComparisonInstruction
	{
		public Cgt(ILInstruction left, ILInstruction right) : base(OpCode.Cgt, left, right)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitCgt(this);
		}
	}
	/// Compare greater than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.
	public sealed partial class Cgt_Un : BinaryComparisonInstruction
	{
		public Cgt_Un(ILInstruction left, ILInstruction right) : base(OpCode.Cgt_Un, left, right)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitCgt_Un(this);
		}
	}
	/// Compare less than. For integers, perform a signed comparison. For floating-point numbers, return 0 for unordered numbers.
	public sealed partial class Clt : BinaryComparisonInstruction
	{
		public Clt(ILInstruction left, ILInstruction right) : base(OpCode.Clt, left, right)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitClt(this);
		}
	}
	/// Compare less than (unordered/unsigned). For integers, perform a signed comparison. For floating-point numbers, return 1 for unordered numbers.
	public sealed partial class Clt_Un : BinaryComparisonInstruction
	{
		public Clt_Un(ILInstruction left, ILInstruction right) : base(OpCode.Clt_Un, left, right)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitClt_Un(this);
		}
	}
	/// Non-virtual method call.
	public sealed partial class Call : CallInstruction
	{
		public Call(MethodReference method) : base(OpCode.Call, method)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitCall(this);
		}
	}
	/// Virtual method call.
	public sealed partial class CallVirt : CallInstruction
	{
		public CallVirt(MethodReference method) : base(OpCode.CallVirt, method)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitCallVirt(this);
		}
	}
	/// Checks that the float on top of the stack is not NaN or infinite.
	public sealed partial class Ckfinite : SimpleInstruction
	{
		public Ckfinite() : base(OpCode.Ckfinite)
		{
		}
		public override StackType ResultType { get { return StackType.Void; } }
		protected override InstructionFlags ComputeFlags()
		{
			return InstructionFlags.MayPeek | InstructionFlags.MayThrow;
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitCkfinite(this);
		}
	}
	/// Numeric cast.
	public sealed partial class Conv : UnaryInstruction
	{
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitConv(this);
		}
	}
	/// Loads the value of a local variable. (ldarg/ldloc)
	public sealed partial class LdLoc : SimpleInstruction
	{
		public LdLoc(ILVariable variable) : base(OpCode.LdLoc)
		{
			Debug.Assert(variable != null);
			this.variable = variable;
		}
		readonly ILVariable variable;
		/// Returns the variable operand.
		public ILVariable Variable { get { return variable; } }
		public override StackType ResultType { get { return variable.Type.GetStackType(); } }
		public override void WriteTo(ITextOutput output)
		{
			output.Write(OpCode);
			output.Write(' ');
			variable.WriteTo(output);
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdLoc(this);
		}
	}
	/// Loads the address of a local variable. (ldarga/ldloca)
	public sealed partial class LdLoca : SimpleInstruction
	{
		public LdLoca(ILVariable variable) : base(OpCode.LdLoca)
		{
			Debug.Assert(variable != null);
			this.variable = variable;
		}
		public override StackType ResultType { get { return StackType.Ref; } }
		readonly ILVariable variable;
		/// Returns the variable operand.
		public ILVariable Variable { get { return variable; } }
		public override void WriteTo(ITextOutput output)
		{
			output.Write(OpCode);
			output.Write(' ');
			variable.WriteTo(output);
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdLoca(this);
		}
	}
	/// Stores a value into a local variable. (starg/stloc)
	public sealed partial class StLoc : ILInstruction
	{
		public StLoc(ILInstruction value, ILVariable variable) : base(OpCode.StLoc)
		{
			this.Value = value;
			Debug.Assert(variable != null);
			this.variable = variable;
		}
		ILInstruction value;
		public ILInstruction Value {
			get { return this.value; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.value, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.value;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Value = this.value.AcceptVisitor(visitor);
		}
		internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack instructionStack, out bool finished)
		{
			this.Value = this.value.Inline(flagsBefore, instructionStack, out finished);
			return this;
		}
		readonly ILVariable variable;
		/// Returns the variable operand.
		public ILVariable Variable { get { return variable; } }
		public override StackType ResultType { get { return variable.Type.GetStackType(); } }
		protected override InstructionFlags ComputeFlags()
		{
			return value.Flags;
		}
		public override void WriteTo(ITextOutput output)
		{
			output.Write(OpCode);
			output.Write(' ');
			variable.WriteTo(output);
			output.Write('(');
			this.value.WriteTo(output);
			output.Write(')');
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitStLoc(this);
		}
	}
	/// 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdStr(this);
		}
	}
	/// 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdcI4(this);
		}
	}
	/// 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdcI8(this);
		}
	}
	/// 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdcF(this);
		}
	}
	/// 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdNull(this);
		}
	}
	/// Load method pointer
	public sealed partial class LdFtn : SimpleInstruction
	{
		public LdFtn(MethodReference method) : base(OpCode.LdFtn)
		{
			this.method = method;
		}
		readonly MethodReference method;
		/// Returns the method operand.
		public MethodReference 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdFtn(this);
		}
	}
	/// Load method pointer
	public sealed partial class LdVirtFtn : UnaryInstruction
	{
		public LdVirtFtn(ILInstruction argument, MethodReference method) : base(OpCode.LdVirtFtn, argument)
		{
			this.method = method;
		}
		readonly MethodReference method;
		/// Returns the method operand.
		public MethodReference Method { get { return method; } }
		public override StackType ResultType { get { return StackType.I; } }
		protected override InstructionFlags ComputeFlags()
		{
			return base.ComputeFlags() | 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdVirtFtn(this);
		}
	}
	/// Loads runtime representation of metadata token
	public sealed partial class LdToken : SimpleInstruction
	{
		public LdToken(MemberReference member) : base(OpCode.LdToken)
		{
			this.member = member;
		}
		readonly MemberReference member;
		/// Returns the token operand.
		public MemberReference 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdToken(this);
		}
	}
	/// 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLocAlloc(this);
		}
	}
	/// Returns from the current method or lambda.
	public sealed partial class Return : ILInstruction
	{
		public override StackType ResultType { get { return StackType.Void; } }
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitReturn(this);
		}
	}
	/// Shift left
	public sealed partial class Shl : BinaryNumericInstruction
	{
		public Shl(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Shl, left, right, checkForOverflow, sign)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitShl(this);
		}
	}
	/// Shift right
	public sealed partial class Shr : BinaryNumericInstruction
	{
		public Shr(ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : base(OpCode.Shr, left, right, checkForOverflow, sign)
		{
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitShr(this);
		}
	}
	/// Load instance field
	public sealed partial class LdFld : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
	{
		public LdFld(ILInstruction target, FieldReference field) : base(OpCode.LdFld)
		{
			this.Target = target;
			this.field = field;
		}
		ILInstruction target;
		public ILInstruction Target {
			get { return this.target; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.target, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.target;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Target = this.target.AcceptVisitor(visitor);
		}
		internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack instructionStack, out bool finished)
		{
			this.Target = this.target.Inline(flagsBefore, instructionStack, out finished);
			return this;
		}
		/// 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; }
		readonly FieldReference field;
		/// Returns the field operand.
		public FieldReference Field { get { return field; } }
		public override StackType ResultType { get { return field.FieldType.GetStackType(); } }
		protected override InstructionFlags ComputeFlags()
		{
			return target.Flags | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
		}
		public override void WriteTo(ITextOutput output)
		{
			if (IsVolatile)
				output.Write("volatile.");
			if (UnalignedPrefix > 0)
				output.Write("unaligned(" + UnalignedPrefix + ").");
			output.Write(OpCode);
			output.Write(' ');
			Disassembler.DisassemblerHelpers.WriteOperand(output, field);
			output.Write('(');
			this.target.WriteTo(output);
			output.Write(')');
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdFld(this);
		}
	}
	/// Load address of instance field
	public sealed partial class LdFlda : ILInstruction
	{
		public LdFlda(ILInstruction target, FieldReference field) : base(OpCode.LdFlda)
		{
			this.Target = target;
			this.field = field;
		}
		ILInstruction target;
		public ILInstruction Target {
			get { return this.target; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.target, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.target;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Target = this.target.AcceptVisitor(visitor);
		}
		internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack instructionStack, out bool finished)
		{
			this.Target = this.target.Inline(flagsBefore, instructionStack, out finished);
			return this;
		}
		readonly FieldReference field;
		/// Returns the field operand.
		public FieldReference Field { get { return field; } }
		public override StackType ResultType { get { return StackType.Ref; } }
		protected override InstructionFlags ComputeFlags()
		{
			return target.Flags | 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdFlda(this);
		}
	}
	/// Store value to instance field
	public sealed partial class StFld : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
	{
		public StFld(ILInstruction target, ILInstruction value, FieldReference field) : base(OpCode.StFld)
		{
			this.Target = target;
			this.Value = value;
			this.field = field;
		}
		ILInstruction target;
		public ILInstruction Target {
			get { return this.target; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.target, value);
			}
		}
		ILInstruction value;
		public ILInstruction Value {
			get { return this.value; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.value, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.target;
				yield return this.value;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Target = this.target.AcceptVisitor(visitor);
			this.Value = this.value.AcceptVisitor(visitor);
		}
		internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack instructionStack, out bool finished)
		{
			this.Value = this.value.Inline(flagsBefore | ((this.target.Flags) & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop)), instructionStack, out finished);
			if (finished)
				this.Target = this.target.Inline(flagsBefore, instructionStack, out finished);
			return this;
		}
		/// 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; }
		readonly FieldReference field;
		/// Returns the field operand.
		public FieldReference Field { get { return field; } }
		public override StackType ResultType { get { return field.FieldType.GetStackType(); } }
		protected override InstructionFlags ComputeFlags()
		{
			return target.Flags | value.Flags | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
		}
		public override void WriteTo(ITextOutput output)
		{
			if (IsVolatile)
				output.Write("volatile.");
			if (UnalignedPrefix > 0)
				output.Write("unaligned(" + UnalignedPrefix + ").");
			output.Write(OpCode);
			output.Write(' ');
			Disassembler.DisassemblerHelpers.WriteOperand(output, field);
			output.Write('(');
			this.target.WriteTo(output);
			output.Write(", ");
			this.value.WriteTo(output);
			output.Write(')');
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitStFld(this);
		}
	}
	/// Load static field
	public sealed partial class LdsFld : SimpleInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
	{
		public LdsFld(FieldReference field) : base(OpCode.LdsFld)
		{
			this.field = field;
		}
		/// 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; }
		readonly FieldReference field;
		/// Returns the field operand.
		public FieldReference Field { get { return field; } }
		public override StackType ResultType { get { return field.FieldType.GetStackType(); } }
		protected override InstructionFlags ComputeFlags()
		{
			return InstructionFlags.SideEffect;
		}
		public override void WriteTo(ITextOutput output)
		{
			if (IsVolatile)
				output.Write("volatile.");
			if (UnalignedPrefix > 0)
				output.Write("unaligned(" + UnalignedPrefix + ").");
			output.Write(OpCode);
			output.Write(' ');
			Disassembler.DisassemblerHelpers.WriteOperand(output, field);
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdsFld(this);
		}
	}
	/// Load static field address
	public sealed partial class LdsFlda : SimpleInstruction
	{
		public LdsFlda(FieldReference field) : base(OpCode.LdsFlda)
		{
			this.field = field;
		}
		public override StackType ResultType { get { return StackType.Ref; } }
		readonly FieldReference field;
		/// Returns the field operand.
		public FieldReference Field { get { return field; } }
		public override void WriteTo(ITextOutput output)
		{
			output.Write(OpCode);
			output.Write(' ');
			Disassembler.DisassemblerHelpers.WriteOperand(output, field);
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdsFlda(this);
		}
	}
	/// Store value to static field
	public sealed partial class StsFld : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
	{
		public StsFld(ILInstruction value, FieldReference field) : base(OpCode.StsFld)
		{
			this.Value = value;
			this.field = field;
		}
		ILInstruction value;
		public ILInstruction Value {
			get { return this.value; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.value, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.value;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Value = this.value.AcceptVisitor(visitor);
		}
		internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack instructionStack, out bool finished)
		{
			this.Value = this.value.Inline(flagsBefore, instructionStack, out finished);
			return this;
		}
		/// 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; }
		readonly FieldReference field;
		/// Returns the field operand.
		public FieldReference Field { get { return field; } }
		public override StackType ResultType { get { return field.FieldType.GetStackType(); } }
		protected override InstructionFlags ComputeFlags()
		{
			return value.Flags | InstructionFlags.SideEffect;
		}
		public override void WriteTo(ITextOutput output)
		{
			if (IsVolatile)
				output.Write("volatile.");
			if (UnalignedPrefix > 0)
				output.Write("unaligned(" + UnalignedPrefix + ").");
			output.Write(OpCode);
			output.Write(' ');
			Disassembler.DisassemblerHelpers.WriteOperand(output, field);
			output.Write('(');
			this.value.WriteTo(output);
			output.Write(')');
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitStsFld(this);
		}
	}
	/// Casts an object to a class.
	public sealed partial class CastClass : UnaryInstruction
	{
		public CastClass(ILInstruction argument, TypeReference type) : base(OpCode.CastClass, argument)
		{
			this.type = type;
		}
		readonly TypeReference type;
		/// Returns the type operand.
		public TypeReference Type { get { return type; } }
		public override StackType ResultType { get { return type.GetStackType(); } }
		protected override InstructionFlags ComputeFlags()
		{
			return base.ComputeFlags() | InstructionFlags.MayThrow;
		}
		public override void WriteTo(ITextOutput output)
		{
			output.Write(OpCode);
			output.Write(' ');
			Disassembler.DisassemblerHelpers.WriteOperand(output, type);
			output.Write('(');
			Argument.WriteTo(output);
			output.Write(')');
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitCastClass(this);
		}
	}
	/// Test if object is instance of class or interface.
	public sealed partial class IsInst : UnaryInstruction
	{
		public IsInst(ILInstruction argument, TypeReference type) : base(OpCode.IsInst, argument)
		{
			this.type = type;
		}
		readonly TypeReference type;
		/// Returns the type operand.
		public TypeReference 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitIsInst(this);
		}
	}
	/// Indirect load (ref/pointer dereference).
	public sealed partial class LdObj : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
	{
		public LdObj(ILInstruction target, TypeReference type) : base(OpCode.LdObj)
		{
			this.Target = target;
			this.type = type;
		}
		ILInstruction target;
		public ILInstruction Target {
			get { return this.target; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.target, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.target;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Target = this.target.AcceptVisitor(visitor);
		}
		internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack instructionStack, out bool finished)
		{
			this.Target = this.target.Inline(flagsBefore, instructionStack, out finished);
			return this;
		}
		readonly TypeReference type;
		/// Returns the type operand.
		public TypeReference 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 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdObj(this);
		}
	}
	/// Indirect store (store to ref/pointer).
	public sealed partial class StObj : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
	{
		public StObj(ILInstruction target, ILInstruction value, TypeReference type) : base(OpCode.StObj)
		{
			this.Target = target;
			this.Value = value;
			this.type = type;
		}
		ILInstruction target;
		public ILInstruction Target {
			get { return this.target; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.target, value);
			}
		}
		ILInstruction value;
		public ILInstruction Value {
			get { return this.value; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.value, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.target;
				yield return this.value;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Target = this.target.AcceptVisitor(visitor);
			this.Value = this.value.AcceptVisitor(visitor);
		}
		internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack instructionStack, out bool finished)
		{
			this.Value = this.value.Inline(flagsBefore | ((this.target.Flags) & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop)), instructionStack, out finished);
			if (finished)
				this.Target = this.target.Inline(flagsBefore, instructionStack, out finished);
			return this;
		}
		readonly TypeReference type;
		/// Returns the type operand.
		public TypeReference 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 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitStObj(this);
		}
	}
	/// Boxes a value.
	public sealed partial class Box : UnaryInstruction
	{
		public Box(ILInstruction argument, TypeReference type) : base(OpCode.Box, argument)
		{
			this.type = type;
		}
		readonly TypeReference type;
		/// Returns the type operand.
		public TypeReference 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 void WriteTo(ITextOutput output)
		{
			output.Write(OpCode);
			output.Write(' ');
			Disassembler.DisassemblerHelpers.WriteOperand(output, type);
			output.Write('(');
			Argument.WriteTo(output);
			output.Write(')');
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitBox(this);
		}
	}
	/// Compute address inside box.
	public sealed partial class Unbox : UnaryInstruction
	{
		public Unbox(ILInstruction argument, TypeReference type) : base(OpCode.Unbox, argument)
		{
			this.type = type;
		}
		readonly TypeReference type;
		/// Returns the type operand.
		public TypeReference Type { get { return type; } }
		public override StackType ResultType { get { return StackType.Ref; } }
		protected override InstructionFlags ComputeFlags()
		{
			return base.ComputeFlags() | InstructionFlags.MayThrow;
		}
		public override void WriteTo(ITextOutput output)
		{
			output.Write(OpCode);
			output.Write(' ');
			Disassembler.DisassemblerHelpers.WriteOperand(output, type);
			output.Write('(');
			Argument.WriteTo(output);
			output.Write(')');
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitUnbox(this);
		}
	}
	/// Unbox a value.
	public sealed partial class UnboxAny : UnaryInstruction
	{
		public UnboxAny(ILInstruction argument, TypeReference type) : base(OpCode.UnboxAny, argument)
		{
			this.type = type;
		}
		readonly TypeReference type;
		/// Returns the type operand.
		public TypeReference Type { get { return type; } }
		public override StackType ResultType { get { return type.GetStackType(); } }
		protected override InstructionFlags ComputeFlags()
		{
			return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
		}
		public override void WriteTo(ITextOutput output)
		{
			output.Write(OpCode);
			output.Write(' ');
			Disassembler.DisassemblerHelpers.WriteOperand(output, type);
			output.Write('(');
			Argument.WriteTo(output);
			output.Write(')');
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitUnboxAny(this);
		}
	}
	/// Creates an object instance and calls the constructor.
	public sealed partial class NewObj : CallInstruction
	{
		public NewObj(MethodReference method) : base(OpCode.NewObj, method)
		{
		}
		public override StackType ResultType { get { return StackType.O; } }
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitNewObj(this);
		}
	}
	/// Initializes the value at an address.
	public sealed partial class InitObj : UnaryInstruction
	{
		public InitObj(ILInstruction argument, TypeReference type) : base(OpCode.InitObj, argument)
		{
			this.type = type;
		}
		readonly TypeReference type;
		/// Returns the type operand.
		public TypeReference Type { get { return type; } }
		public override StackType ResultType { get { return StackType.Void; } }
		public override void WriteTo(ITextOutput output)
		{
			output.Write(OpCode);
			output.Write(' ');
			Disassembler.DisassemblerHelpers.WriteOperand(output, type);
			output.Write('(');
			Argument.WriteTo(output);
			output.Write(')');
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitInitObj(this);
		}
	}
	/// Returns the default value for a type.
	public sealed partial class DefaultValue : SimpleInstruction
	{
		public DefaultValue(TypeReference type) : base(OpCode.DefaultValue)
		{
			this.type = type;
		}
		readonly TypeReference type;
		/// Returns the type operand.
		public TypeReference Type { get { return type; } }
		public override StackType ResultType { get { return type.GetStackType(); } }
		public override void WriteTo(ITextOutput output)
		{
			output.Write(OpCode);
			output.Write(' ');
			Disassembler.DisassemblerHelpers.WriteOperand(output, type);
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitDefaultValue(this);
		}
	}
	/// 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitThrow(this);
		}
	}
	/// 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitRethrow(this);
		}
	}
	/// Gets the size of a type in bytes.
	public sealed partial class SizeOf : SimpleInstruction
	{
		public SizeOf(TypeReference type) : base(OpCode.SizeOf)
		{
			this.type = type;
		}
		readonly TypeReference type;
		/// Returns the type operand.
		public TypeReference 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 T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitSizeOf(this);
		}
	}
	/// Returns the length of an array as 'native unsigned int'.
	public sealed partial class LdLen : ILInstruction
	{
		public LdLen(ILInstruction target) : base(OpCode.LdLen)
		{
			this.Target = target;
		}
		ILInstruction target;
		public ILInstruction Target {
			get { return this.target; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.target, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.target;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Target = this.target.AcceptVisitor(visitor);
		}
		internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack instructionStack, out bool finished)
		{
			this.Target = this.target.Inline(flagsBefore, instructionStack, out finished);
			return this;
		}
		public override StackType ResultType { get { return StackType.I; } }
		protected override InstructionFlags ComputeFlags()
		{
			return target.Flags | InstructionFlags.MayThrow;
		}
		public override void WriteTo(ITextOutput output)
		{
			output.Write(OpCode);
			output.Write('(');
			this.target.WriteTo(output);
			output.Write(')');
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdLen(this);
		}
	}
	/// Load address of array element.
	public sealed partial class LdElema : ILInstruction
	{
		public LdElema(ILInstruction array, ILInstruction index, TypeReference type) : base(OpCode.LdElema)
		{
			this.Array = array;
			this.Index = index;
			this.type = type;
		}
		ILInstruction array;
		public ILInstruction Array {
			get { return this.array; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.array, value);
			}
		}
		ILInstruction index;
		public ILInstruction Index {
			get { return this.index; }
			set {
				ValidateArgument(value);
				SetChildInstruction(ref this.index, value);
			}
		}
		public override IEnumerable Children {
			get {
				yield return this.array;
				yield return this.index;
			}
		}
		public override void TransformChildren(ILVisitor visitor)
		{
			this.Array = this.array.AcceptVisitor(visitor);
			this.Index = this.index.AcceptVisitor(visitor);
		}
		internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack instructionStack, out bool finished)
		{
			this.Index = this.index.Inline(flagsBefore | ((this.array.Flags) & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop)), instructionStack, out finished);
			if (finished)
				this.Array = this.array.Inline(flagsBefore, instructionStack, out finished);
			return this;
		}
		readonly TypeReference type;
		/// Returns the type operand.
		public TypeReference Type { get { return type; } }
		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 | index.Flags | 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);
			output.Write(", ");
			this.index.WriteTo(output);
			output.Write(')');
		}
		public override T AcceptVisitor(ILVisitor visitor)
		{
			return visitor.VisitLdElema(this);
		}
	}
	/// 
	/// Base class for visitor pattern.
	/// 
	public abstract class ILVisitor
	{
		/// Called by Visit*() methods that were not overridden
		protected abstract T Default(ILInstruction inst);
		
		protected internal virtual T VisitNop(Nop inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitPop(Pop inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitPeek(Peek inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitVoid(Void inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitILFunction(ILFunction function)
		{
			return Default(function);
		}
		protected internal virtual T VisitBlockContainer(BlockContainer container)
		{
			return Default(container);
		}
		protected internal virtual T VisitBlock(Block block)
		{
			return Default(block);
		}
		protected internal virtual T VisitLogicNot(LogicNot inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitAdd(Add inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitSub(Sub inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitMul(Mul inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitDiv(Div inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitRem(Rem inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitBitAnd(BitAnd inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitBitOr(BitOr inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitBitXor(BitXor inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitBitNot(BitNot inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitArglist(Arglist inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitBranch(Branch inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitEndFinally(EndFinally inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitIfInstruction(IfInstruction inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitTryCatch(TryCatch inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitTryCatchHandler(TryCatchHandler inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitTryFinally(TryFinally inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitTryFault(TryFault inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitDebugBreak(DebugBreak inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitCeq(Ceq inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitCgt(Cgt inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitCgt_Un(Cgt_Un inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitClt(Clt inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitClt_Un(Clt_Un inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitCall(Call inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitCallVirt(CallVirt inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitCkfinite(Ckfinite inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitConv(Conv inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdLoc(LdLoc inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdLoca(LdLoca inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitStLoc(StLoc inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdStr(LdStr inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdcI4(LdcI4 inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdcI8(LdcI8 inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdcF(LdcF inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdNull(LdNull inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdFtn(LdFtn inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdVirtFtn(LdVirtFtn inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdToken(LdToken inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLocAlloc(LocAlloc inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitReturn(Return inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitShl(Shl inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitShr(Shr inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdFld(LdFld inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdFlda(LdFlda inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitStFld(StFld inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdsFld(LdsFld inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdsFlda(LdsFlda inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitStsFld(StsFld inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitCastClass(CastClass inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitIsInst(IsInst inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdObj(LdObj inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitStObj(StObj inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitBox(Box inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitUnbox(Unbox inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitUnboxAny(UnboxAny inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitNewObj(NewObj inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitInitObj(InitObj inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitDefaultValue(DefaultValue inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitThrow(Throw inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitRethrow(Rethrow inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitSizeOf(SizeOf inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdLen(LdLen inst)
		{
			return Default(inst);
		}
		protected internal virtual T VisitLdElema(LdElema inst)
		{
			return Default(inst);
		}
	}
	
	partial class BinaryNumericInstruction
	{
		public static BinaryNumericInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign)
		{
			switch (opCode) {
				case OpCode.Add:
					return new Add(left, right, checkForOverflow, sign);
				case OpCode.Sub:
					return new Sub(left, right, checkForOverflow, sign);
				case OpCode.Mul:
					return new Mul(left, right, checkForOverflow, sign);
				case OpCode.Div:
					return new Div(left, right, checkForOverflow, sign);
				case OpCode.Rem:
					return new Rem(left, right, checkForOverflow, sign);
				case OpCode.BitAnd:
					return new BitAnd(left, right, checkForOverflow, sign);
				case OpCode.BitOr:
					return new BitOr(left, right, checkForOverflow, sign);
				case OpCode.BitXor:
					return new BitXor(left, right, checkForOverflow, sign);
				case OpCode.Shl:
					return new Shl(left, right, checkForOverflow, sign);
				case OpCode.Shr:
					return new Shr(left, right, checkForOverflow, sign);
				default:
					throw new ArgumentException("opCode is not a binary numeric instruction");
			}
		}
	}
	
	partial class BinaryComparisonInstruction
	{
		public static BinaryComparisonInstruction Create(OpCode opCode, ILInstruction left, ILInstruction right)
		{
			switch (opCode) {
				case OpCode.Ceq:
					return new Ceq(left, right);
				case OpCode.Cgt:
					return new Cgt(left, right);
				case OpCode.Cgt_Un:
					return new Cgt_Un(left, right);
				case OpCode.Clt:
					return new Clt(left, right);
				case OpCode.Clt_Un:
					return new Clt_Un(left, right);
				default:
					throw new ArgumentException("opCode is not a binary comparison instruction");
			}
		}
	}
	
	partial class InstructionOutputExtensions
	{
		static readonly string[] originalOpCodeNames = {
			"nop",
			"pop",
			"peek",
			"void",
			"ILFunction",
			"BlockContainer",
			"Block",
			"logic.not",
			"add",
			"sub",
			"mul",
			"div",
			"rem",
			"bit.and",
			"bit.or",
			"bit.xor",
			"bit.not",
			"arglist",
			"br",
			"endfinally",
			"if",
			"try.catch",
			"try.catch.handler",
			"try.finally",
			"try.fault",
			"debug.break",
			"ceq",
			"cgt",
			"cgt.un",
			"clt",
			"clt.un",
			"call",
			"callvirt",
			"ckfinite",
			"conv",
			"ldloc",
			"ldloca",
			"stloc",
			"ldstr",
			"ldc.i4",
			"ldc.i8",
			"ldc.f",
			"ldnull",
			"ldftn",
			"ldvirtftn",
			"ldtoken",
			"localloc",
			"ret",
			"shl",
			"shr",
			"ldfld",
			"ldflda",
			"stfld",
			"ldsfld",
			"ldsflda",
			"stsfld",
			"castclass",
			"isinst",
			"ldobj",
			"stobj",
			"box",
			"unbox",
			"unbox.any",
			"newobj",
			"initobj",
			"default.value",
			"throw",
			"rethrow",
			"sizeof",
			"ldlen",
			"ldelema",
		};
	}
}