diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs index fc085325b..45dd53dc9 100644 --- a/ICSharpCode.Decompiler/DecompilerSettings.cs +++ b/ICSharpCode.Decompiler/DecompilerSettings.cs @@ -59,7 +59,7 @@ namespace ICSharpCode.Decompiler expressionTrees = false; } if (languageVersion < CSharp.LanguageVersion.CSharp4) { - // * dynamic (not supported yet) + dynamicExpressions = false; // * named and optional arguments (not supported yet) } if (languageVersion < CSharp.LanguageVersion.CSharp5) { @@ -172,6 +172,21 @@ namespace ICSharpCode.Decompiler } } + bool dynamicExpressions = true; + + /// + /// Decompile expressions that use dynamic types. + /// + public bool DynamicExpressions { + get { return dynamicExpressions; } + set { + if (dynamicExpressions != value) { + dynamicExpressions = value; + OnPropertyChanged(); + } + } + } + bool fixedBuffers = true; /// diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index f88839143..019fe26ce 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -183,6 +183,28 @@ namespace ICSharpCode.Decompiler.IL StringToInt, /// ILAst representation of Expression.Convert. ExpressionTreeCast, + /// ILAst representation of a binary operator inside a dynamic expression (maps to Binder.BinaryOperation). + DynamicBinaryOperatorInstruction, + /// ILAst representation of a unary operator inside a dynamic expression (maps to Binder.UnaryOperation). + DynamicUnaryOperatorInstruction, + /// ILAst representation of a cast inside a dynamic expression (maps to Binder.Convert). + DynamicConvertInstruction, + /// ILAst representation of a property get method call inside a dynamic expression (maps to Binder.GetMember). + DynamicGetMemberInstruction, + /// ILAst representation of a property set method call inside a dynamic expression (maps to Binder.SetMember). + DynamicSetMemberInstruction, + /// ILAst representation of an indexer get method call inside a dynamic expression (maps to Binder.GetIndex). + DynamicGetIndexInstruction, + /// ILAst representation of an indexer set method call inside a dynamic expression (maps to Binder.SetIndex). + DynamicSetIndexInstruction, + /// ILAst representation of a method call inside a dynamic expression (maps to Binder.InvokeMember). + DynamicInvokeMemberInstruction, + /// ILAst representation of a constuctor invocation inside a dynamic expression (maps to Binder.InvokeConstructor). + DynamicInvokeConstructorInstruction, + /// ILAst representation of a delegate invocation inside a dynamic expression (maps to Binder.Invoke). + DynamicInvokeInstruction, + /// ILAst representation of a call to the Binder.IsEvent method inside a dynamic expression. + DynamicIsEventInstruction, /// Push a typed reference of type class onto the stack. MakeRefAny, /// Push the type token stored in a typed reference. @@ -473,6 +495,26 @@ namespace ICSharpCode.Decompiler.IL } } } +namespace ICSharpCode.Decompiler.IL +{ + /// Instruction representing a dynamic call site. + public abstract partial class DynamicInstruction : ILInstruction + { + protected DynamicInstruction(OpCode opCode) : base(opCode) + { + } + + protected override InstructionFlags ComputeFlags() + { + return 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. @@ -4701,147 +4743,199 @@ namespace ICSharpCode.Decompiler.IL } namespace ICSharpCode.Decompiler.IL { - /// Push a typed reference of type class onto the stack. - public sealed partial class MakeRefAny : UnaryInstruction + /// ILAst representation of a binary operator inside a dynamic expression (maps to Binder.BinaryOperation). + public sealed partial class DynamicBinaryOperatorInstruction : DynamicInstruction { - public MakeRefAny(ILInstruction argument, IType type) : base(OpCode.MakeRefAny, argument) - { - this.type = type; + 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); + } } - IType type; - /// Returns the type operand. - public IType Type { - get { return type; } - set { type = value; InvalidateFlags(); } + 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); + } } - public override StackType ResultType { get { return StackType.O; } } - public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + protected sealed override int GetChildCount() { - ILRange.WriteTo(output, options); - output.Write(OpCode); - output.Write(' '); - type.WriteTo(output); - output.Write('('); - Argument.WriteTo(output, options); - output.Write(')'); + return 2; } - public override void AcceptVisitor(ILVisitor visitor) + protected sealed override ILInstruction GetChild(int index) { - visitor.VisitMakeRefAny(this); + switch (index) { + case 0: + return this.left; + case 1: + return this.right; + default: + throw new IndexOutOfRangeException(); + } } - public override T AcceptVisitor(ILVisitor visitor) + protected sealed override void SetChild(int index, ILInstruction value) { - return visitor.VisitMakeRefAny(this); + switch (index) { + case 0: + this.Left = value; + break; + case 1: + this.Right = value; + break; + default: + throw new IndexOutOfRangeException(); + } } - public override T AcceptVisitor(ILVisitor visitor, C context) + protected sealed override SlotInfo GetChildSlot(int index) { - return visitor.VisitMakeRefAny(this, context); + switch (index) { + case 0: + return LeftSlot; + case 1: + return RightSlot; + default: + throw new IndexOutOfRangeException(); + } } - protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + public sealed override ILInstruction Clone() { - var o = other as MakeRefAny; - return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type); + var clone = (DynamicBinaryOperatorInstruction)ShallowClone(); + clone.Left = this.left.Clone(); + clone.Right = this.right.Clone(); + return clone; } - } -} -namespace ICSharpCode.Decompiler.IL -{ - /// Push the type token stored in a typed reference. - public sealed partial class RefAnyType : UnaryInstruction - { - public RefAnyType(ILInstruction argument) : base(OpCode.RefAnyType, argument) + protected override InstructionFlags ComputeFlags() { + return base.ComputeFlags() | left.Flags | right.Flags; + } + public override InstructionFlags DirectFlags { + get { + return base.DirectFlags; + } } - public override StackType ResultType { get { return StackType.O; } } public override void AcceptVisitor(ILVisitor visitor) { - visitor.VisitRefAnyType(this); + visitor.VisitDynamicBinaryOperatorInstruction(this); } public override T AcceptVisitor(ILVisitor visitor) { - return visitor.VisitRefAnyType(this); + return visitor.VisitDynamicBinaryOperatorInstruction(this); } public override T AcceptVisitor(ILVisitor visitor, C context) { - return visitor.VisitRefAnyType(this, context); + return visitor.VisitDynamicBinaryOperatorInstruction(this, context); } protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) { - var o = other as RefAnyType; - return o != null && this.Argument.PerformMatch(o.Argument, ref match); + var o = other as DynamicBinaryOperatorInstruction; + return o != null && this.left.PerformMatch(o.left, ref match) && this.right.PerformMatch(o.right, ref match); } } } namespace ICSharpCode.Decompiler.IL { - /// Push the address stored in a typed reference. - public sealed partial class RefAnyValue : UnaryInstruction + /// ILAst representation of a unary operator inside a dynamic expression (maps to Binder.UnaryOperation). + public sealed partial class DynamicUnaryOperatorInstruction : DynamicInstruction { - public RefAnyValue(ILInstruction argument, IType type) : base(OpCode.RefAnyValue, argument) + public static readonly SlotInfo OperandSlot = new SlotInfo("Operand", canInlineInto: true); + ILInstruction operand; + public ILInstruction Operand { + get { return this.operand; } + set { + ValidateChild(value); + SetChildInstruction(ref this.operand, value, 0); + } + } + protected sealed override int GetChildCount() { - this.type = type; + return 1; } - IType type; - /// Returns the type operand. - public IType Type { - get { return type; } - set { type = value; InvalidateFlags(); } + protected sealed override ILInstruction GetChild(int index) + { + switch (index) { + case 0: + return this.operand; + default: + throw new IndexOutOfRangeException(); + } + } + protected sealed override void SetChild(int index, ILInstruction value) + { + switch (index) { + case 0: + this.Operand = value; + break; + default: + throw new IndexOutOfRangeException(); + } + } + protected sealed override SlotInfo GetChildSlot(int index) + { + switch (index) { + case 0: + return OperandSlot; + default: + throw new IndexOutOfRangeException(); + } + } + public sealed override ILInstruction Clone() + { + var clone = (DynamicUnaryOperatorInstruction)ShallowClone(); + clone.Operand = this.operand.Clone(); + return clone; } - public override StackType ResultType { get { return StackType.Ref; } } protected override InstructionFlags ComputeFlags() { - return base.ComputeFlags() | InstructionFlags.MayThrow; + return base.ComputeFlags() | operand.Flags; } public override InstructionFlags DirectFlags { get { - return base.DirectFlags | InstructionFlags.MayThrow; + return base.DirectFlags; } } - public override void WriteTo(ITextOutput output, ILAstWritingOptions options) - { - ILRange.WriteTo(output, options); - output.Write(OpCode); - output.Write(' '); - type.WriteTo(output); - output.Write('('); - Argument.WriteTo(output, options); - output.Write(')'); - } public override void AcceptVisitor(ILVisitor visitor) { - visitor.VisitRefAnyValue(this); + visitor.VisitDynamicUnaryOperatorInstruction(this); } public override T AcceptVisitor(ILVisitor visitor) { - return visitor.VisitRefAnyValue(this); + return visitor.VisitDynamicUnaryOperatorInstruction(this); } public override T AcceptVisitor(ILVisitor visitor, C context) { - return visitor.VisitRefAnyValue(this, context); + return visitor.VisitDynamicUnaryOperatorInstruction(this, context); } protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) { - var o = other as RefAnyValue; - return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type); + var o = other as DynamicUnaryOperatorInstruction; + return o != null && this.operand.PerformMatch(o.operand, ref match); } } } namespace ICSharpCode.Decompiler.IL { - /// Yield an element from an iterator. - public sealed partial class YieldReturn : ILInstruction + /// ILAst representation of a cast inside a dynamic expression (maps to Binder.Convert). + public sealed partial class DynamicConvertInstruction : DynamicInstruction { - public YieldReturn(ILInstruction value) : base(OpCode.YieldReturn) - { - this.Value = value; + IType type; + /// Returns the type operand. + public IType Type { + get { return type; } + set { type = value; InvalidateFlags(); } } - public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true); - ILInstruction value; - public ILInstruction Value { - get { return this.value; } + 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.value, value, 0); + SetChildInstruction(ref this.argument, value, 0); } } protected sealed override int GetChildCount() @@ -4852,7 +4946,7 @@ namespace ICSharpCode.Decompiler.IL { switch (index) { case 0: - return this.value; + return this.argument; default: throw new IndexOutOfRangeException(); } @@ -4861,7 +4955,7 @@ namespace ICSharpCode.Decompiler.IL { switch (index) { case 0: - this.Value = value; + this.Argument = value; break; default: throw new IndexOutOfRangeException(); @@ -4871,70 +4965,62 @@ namespace ICSharpCode.Decompiler.IL { switch (index) { case 0: - return ValueSlot; + return ArgumentSlot; default: throw new IndexOutOfRangeException(); } } public sealed override ILInstruction Clone() { - var clone = (YieldReturn)ShallowClone(); - clone.Value = this.value.Clone(); + var clone = (DynamicConvertInstruction)ShallowClone(); + clone.Argument = this.argument.Clone(); return clone; } - public override StackType ResultType { get { return StackType.Void; } } protected override InstructionFlags ComputeFlags() { - return InstructionFlags.MayBranch | InstructionFlags.SideEffect | value.Flags; + return base.ComputeFlags() | InstructionFlags.MayThrow | argument.Flags; } public override InstructionFlags DirectFlags { get { - return InstructionFlags.MayBranch | InstructionFlags.SideEffect; + return base.DirectFlags | InstructionFlags.MayThrow; } } - public override void WriteTo(ITextOutput output, ILAstWritingOptions options) - { - ILRange.WriteTo(output, options); - output.Write(OpCode); - output.Write('('); - this.value.WriteTo(output, options); - output.Write(')'); - } public override void AcceptVisitor(ILVisitor visitor) { - visitor.VisitYieldReturn(this); + visitor.VisitDynamicConvertInstruction(this); } public override T AcceptVisitor(ILVisitor visitor) { - return visitor.VisitYieldReturn(this); + return visitor.VisitDynamicConvertInstruction(this); } public override T AcceptVisitor(ILVisitor visitor, C context) { - return visitor.VisitYieldReturn(this, context); + return visitor.VisitDynamicConvertInstruction(this, context); } protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) { - var o = other as YieldReturn; - return o != null && this.value.PerformMatch(o.value, ref match); + var o = other as DynamicConvertInstruction; + return o != null && type.Equals(o.type) && this.argument.PerformMatch(o.argument, ref match); + } + internal override void CheckInvariant(ILPhase phase) + { + base.CheckInvariant(phase); + Debug.Assert(argument.ResultType == StackType.O); } } } namespace ICSharpCode.Decompiler.IL { - /// C# await operator. - public sealed partial class Await : ILInstruction + /// ILAst representation of a property get method call inside a dynamic expression (maps to Binder.GetMember). + public sealed partial class DynamicGetMemberInstruction : DynamicInstruction { - public Await(ILInstruction value) : base(OpCode.Await) - { - this.Value = value; - } - public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true); - ILInstruction value; - public ILInstruction Value { - get { return this.value; } + 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.value, value, 0); + SetChildInstruction(ref this.target, value, 0); } } protected sealed override int GetChildCount() @@ -4945,7 +5031,7 @@ namespace ICSharpCode.Decompiler.IL { switch (index) { case 0: - return this.value; + return this.target; default: throw new IndexOutOfRangeException(); } @@ -4954,7 +5040,7 @@ namespace ICSharpCode.Decompiler.IL { switch (index) { case 0: - this.Value = value; + this.Target = value; break; default: throw new IndexOutOfRangeException(); @@ -4964,25 +5050,861 @@ namespace ICSharpCode.Decompiler.IL { switch (index) { case 0: - return ValueSlot; + return TargetSlot; default: throw new IndexOutOfRangeException(); } } public sealed override ILInstruction Clone() { - var clone = (Await)ShallowClone(); - clone.Value = this.value.Clone(); + var clone = (DynamicGetMemberInstruction)ShallowClone(); + clone.Target = this.target.Clone(); return clone; } - public override StackType ResultType { get { return GetResultMethod?.ReturnType.GetStackType() ?? StackType.Unknown; } } protected override InstructionFlags ComputeFlags() { - return InstructionFlags.SideEffect | value.Flags; + return base.ComputeFlags() | InstructionFlags.MayThrow | target.Flags; } public override InstructionFlags DirectFlags { get { - return InstructionFlags.SideEffect; + return base.DirectFlags | InstructionFlags.MayThrow; + } + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitDynamicGetMemberInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitDynamicGetMemberInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitDynamicGetMemberInstruction(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as DynamicGetMemberInstruction; + return o != null && this.target.PerformMatch(o.target, ref match); + } + internal override void CheckInvariant(ILPhase phase) + { + base.CheckInvariant(phase); + Debug.Assert(target.ResultType == StackType.O); + } + } +} +namespace ICSharpCode.Decompiler.IL +{ + /// ILAst representation of a property set method call inside a dynamic expression (maps to Binder.SetMember). + public sealed partial class DynamicSetMemberInstruction : DynamicInstruction + { + 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 = (DynamicSetMemberInstruction)ShallowClone(); + clone.Target = this.target.Clone(); + clone.Value = this.value.Clone(); + return clone; + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow | target.Flags | value.Flags; + } + public override InstructionFlags DirectFlags { + get { + return base.DirectFlags | InstructionFlags.MayThrow; + } + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitDynamicSetMemberInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitDynamicSetMemberInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitDynamicSetMemberInstruction(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as DynamicSetMemberInstruction; + return o != null && this.target.PerformMatch(o.target, ref match) && this.value.PerformMatch(o.value, ref match); + } + internal override void CheckInvariant(ILPhase phase) + { + base.CheckInvariant(phase); + Debug.Assert(target.ResultType == StackType.O); + } + } +} +namespace ICSharpCode.Decompiler.IL +{ + /// ILAst representation of an indexer get method call inside a dynamic expression (maps to Binder.GetIndex). + public sealed partial class DynamicGetIndexInstruction : DynamicInstruction + { + 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 = (DynamicGetIndexInstruction)ShallowClone(); + clone.Arguments = new InstructionCollection(clone, 0); + clone.Arguments.AddRange(this.Arguments.Select(arg => arg.Clone())); + return clone; + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow | Arguments.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags); + } + public override InstructionFlags DirectFlags { + get { + return base.DirectFlags | InstructionFlags.MayThrow; + } + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitDynamicGetIndexInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitDynamicGetIndexInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitDynamicGetIndexInstruction(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as DynamicGetIndexInstruction; + return o != null && Patterns.ListMatch.DoMatch(this.Arguments, o.Arguments, ref match); + } + } +} +namespace ICSharpCode.Decompiler.IL +{ + /// ILAst representation of an indexer set method call inside a dynamic expression (maps to Binder.SetIndex). + public sealed partial class DynamicSetIndexInstruction : DynamicInstruction + { + 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 = (DynamicSetIndexInstruction)ShallowClone(); + clone.Arguments = new InstructionCollection(clone, 0); + clone.Arguments.AddRange(this.Arguments.Select(arg => arg.Clone())); + return clone; + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow | Arguments.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags); + } + public override InstructionFlags DirectFlags { + get { + return base.DirectFlags | InstructionFlags.MayThrow; + } + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitDynamicSetIndexInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitDynamicSetIndexInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitDynamicSetIndexInstruction(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as DynamicSetIndexInstruction; + return o != null && Patterns.ListMatch.DoMatch(this.Arguments, o.Arguments, ref match); + } + } +} +namespace ICSharpCode.Decompiler.IL +{ + /// ILAst representation of a method call inside a dynamic expression (maps to Binder.InvokeMember). + public sealed partial class DynamicInvokeMemberInstruction : DynamicInstruction + { + 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 = (DynamicInvokeMemberInstruction)ShallowClone(); + clone.Arguments = new InstructionCollection(clone, 0); + clone.Arguments.AddRange(this.Arguments.Select(arg => arg.Clone())); + return clone; + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow | Arguments.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags); + } + public override InstructionFlags DirectFlags { + get { + return base.DirectFlags | InstructionFlags.MayThrow; + } + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitDynamicInvokeMemberInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitDynamicInvokeMemberInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitDynamicInvokeMemberInstruction(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as DynamicInvokeMemberInstruction; + return o != null && Patterns.ListMatch.DoMatch(this.Arguments, o.Arguments, ref match); + } + } +} +namespace ICSharpCode.Decompiler.IL +{ + /// ILAst representation of a constuctor invocation inside a dynamic expression (maps to Binder.InvokeConstructor). + public sealed partial class DynamicInvokeConstructorInstruction : DynamicInstruction + { + 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 = (DynamicInvokeConstructorInstruction)ShallowClone(); + clone.Arguments = new InstructionCollection(clone, 0); + clone.Arguments.AddRange(this.Arguments.Select(arg => arg.Clone())); + return clone; + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow | Arguments.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags); + } + public override InstructionFlags DirectFlags { + get { + return base.DirectFlags | InstructionFlags.MayThrow; + } + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitDynamicInvokeConstructorInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitDynamicInvokeConstructorInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitDynamicInvokeConstructorInstruction(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as DynamicInvokeConstructorInstruction; + return o != null && Patterns.ListMatch.DoMatch(this.Arguments, o.Arguments, ref match); + } + } +} +namespace ICSharpCode.Decompiler.IL +{ + /// ILAst representation of a delegate invocation inside a dynamic expression (maps to Binder.Invoke). + public sealed partial class DynamicInvokeInstruction : DynamicInstruction + { + 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 = (DynamicInvokeInstruction)ShallowClone(); + clone.Arguments = new InstructionCollection(clone, 0); + clone.Arguments.AddRange(this.Arguments.Select(arg => arg.Clone())); + return clone; + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow | Arguments.Aggregate(InstructionFlags.None, (f, arg) => f | arg.Flags); + } + public override InstructionFlags DirectFlags { + get { + return base.DirectFlags | InstructionFlags.MayThrow; + } + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitDynamicInvokeInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitDynamicInvokeInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitDynamicInvokeInstruction(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as DynamicInvokeInstruction; + return o != null && Patterns.ListMatch.DoMatch(this.Arguments, o.Arguments, ref match); + } + } +} +namespace ICSharpCode.Decompiler.IL +{ + /// ILAst representation of a call to the Binder.IsEvent method inside a dynamic expression. + public sealed partial class DynamicIsEventInstruction : DynamicInstruction + { + 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 = (DynamicIsEventInstruction)ShallowClone(); + clone.Argument = this.argument.Clone(); + return clone; + } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow | argument.Flags; + } + public override InstructionFlags DirectFlags { + get { + return base.DirectFlags | InstructionFlags.MayThrow; + } + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitDynamicIsEventInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitDynamicIsEventInstruction(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitDynamicIsEventInstruction(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as DynamicIsEventInstruction; + return o != null && this.argument.PerformMatch(o.argument, ref match); + } + internal override void CheckInvariant(ILPhase phase) + { + base.CheckInvariant(phase); + Debug.Assert(argument.ResultType == StackType.O); + } + } +} +namespace ICSharpCode.Decompiler.IL +{ + /// Push a typed reference of type class onto the stack. + public sealed partial class MakeRefAny : UnaryInstruction + { + public MakeRefAny(ILInstruction argument, IType type) : base(OpCode.MakeRefAny, argument) + { + this.type = type; + } + IType type; + /// Returns the type operand. + public IType Type { + get { return type; } + set { type = value; InvalidateFlags(); } + } + public override StackType ResultType { get { return StackType.O; } } + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + output.Write(' '); + type.WriteTo(output); + output.Write('('); + Argument.WriteTo(output, options); + output.Write(')'); + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitMakeRefAny(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitMakeRefAny(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitMakeRefAny(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as MakeRefAny; + return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type); + } + } +} +namespace ICSharpCode.Decompiler.IL +{ + /// Push the type token stored in a typed reference. + public sealed partial class RefAnyType : UnaryInstruction + { + public RefAnyType(ILInstruction argument) : base(OpCode.RefAnyType, argument) + { + } + public override StackType ResultType { get { return StackType.O; } } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitRefAnyType(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitRefAnyType(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitRefAnyType(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as RefAnyType; + return o != null && this.Argument.PerformMatch(o.Argument, ref match); + } + } +} +namespace ICSharpCode.Decompiler.IL +{ + /// Push the address stored in a typed reference. + public sealed partial class RefAnyValue : UnaryInstruction + { + public RefAnyValue(ILInstruction argument, IType type) : base(OpCode.RefAnyValue, argument) + { + this.type = type; + } + IType type; + /// Returns the type operand. + public IType Type { + get { return type; } + set { type = value; InvalidateFlags(); } + } + 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, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + output.Write(' '); + type.WriteTo(output); + output.Write('('); + Argument.WriteTo(output, options); + output.Write(')'); + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitRefAnyValue(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitRefAnyValue(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitRefAnyValue(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as RefAnyValue; + return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type); + } + } +} +namespace ICSharpCode.Decompiler.IL +{ + /// Yield an element from an iterator. + public sealed partial class YieldReturn : ILInstruction + { + public YieldReturn(ILInstruction value) : base(OpCode.YieldReturn) + { + 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 = (YieldReturn)ShallowClone(); + clone.Value = this.value.Clone(); + return clone; + } + public override StackType ResultType { get { return StackType.Void; } } + protected override InstructionFlags ComputeFlags() + { + return InstructionFlags.MayBranch | InstructionFlags.SideEffect | value.Flags; + } + public override InstructionFlags DirectFlags { + get { + return InstructionFlags.MayBranch | InstructionFlags.SideEffect; + } + } + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + output.Write('('); + this.value.WriteTo(output, options); + output.Write(')'); + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitYieldReturn(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitYieldReturn(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitYieldReturn(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as YieldReturn; + return o != null && this.value.PerformMatch(o.value, ref match); + } + } +} +namespace ICSharpCode.Decompiler.IL +{ + /// C# await operator. + public sealed partial class Await : ILInstruction + { + public Await(ILInstruction value) : base(OpCode.Await) + { + 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 = (Await)ShallowClone(); + clone.Value = this.value.Clone(); + return clone; + } + public override StackType ResultType { get { return GetResultMethod?.ReturnType.GetStackType() ?? StackType.Unknown; } } + protected override InstructionFlags ComputeFlags() + { + return InstructionFlags.SideEffect | value.Flags; + } + public override InstructionFlags DirectFlags { + get { + return InstructionFlags.SideEffect; } } public override void WriteTo(ITextOutput output, ILAstWritingOptions options) @@ -5355,6 +6277,50 @@ namespace ICSharpCode.Decompiler.IL { Default(inst); } + protected internal virtual void VisitDynamicBinaryOperatorInstruction(DynamicBinaryOperatorInstruction inst) + { + Default(inst); + } + protected internal virtual void VisitDynamicUnaryOperatorInstruction(DynamicUnaryOperatorInstruction inst) + { + Default(inst); + } + protected internal virtual void VisitDynamicConvertInstruction(DynamicConvertInstruction inst) + { + Default(inst); + } + protected internal virtual void VisitDynamicGetMemberInstruction(DynamicGetMemberInstruction inst) + { + Default(inst); + } + protected internal virtual void VisitDynamicSetMemberInstruction(DynamicSetMemberInstruction inst) + { + Default(inst); + } + protected internal virtual void VisitDynamicGetIndexInstruction(DynamicGetIndexInstruction inst) + { + Default(inst); + } + protected internal virtual void VisitDynamicSetIndexInstruction(DynamicSetIndexInstruction inst) + { + Default(inst); + } + protected internal virtual void VisitDynamicInvokeMemberInstruction(DynamicInvokeMemberInstruction inst) + { + Default(inst); + } + protected internal virtual void VisitDynamicInvokeConstructorInstruction(DynamicInvokeConstructorInstruction inst) + { + Default(inst); + } + protected internal virtual void VisitDynamicInvokeInstruction(DynamicInvokeInstruction inst) + { + Default(inst); + } + protected internal virtual void VisitDynamicIsEventInstruction(DynamicIsEventInstruction inst) + { + Default(inst); + } protected internal virtual void VisitMakeRefAny(MakeRefAny inst) { Default(inst); @@ -5673,6 +6639,50 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst); } + protected internal virtual T VisitDynamicBinaryOperatorInstruction(DynamicBinaryOperatorInstruction inst) + { + return Default(inst); + } + protected internal virtual T VisitDynamicUnaryOperatorInstruction(DynamicUnaryOperatorInstruction inst) + { + return Default(inst); + } + protected internal virtual T VisitDynamicConvertInstruction(DynamicConvertInstruction inst) + { + return Default(inst); + } + protected internal virtual T VisitDynamicGetMemberInstruction(DynamicGetMemberInstruction inst) + { + return Default(inst); + } + protected internal virtual T VisitDynamicSetMemberInstruction(DynamicSetMemberInstruction inst) + { + return Default(inst); + } + protected internal virtual T VisitDynamicGetIndexInstruction(DynamicGetIndexInstruction inst) + { + return Default(inst); + } + protected internal virtual T VisitDynamicSetIndexInstruction(DynamicSetIndexInstruction inst) + { + return Default(inst); + } + protected internal virtual T VisitDynamicInvokeMemberInstruction(DynamicInvokeMemberInstruction inst) + { + return Default(inst); + } + protected internal virtual T VisitDynamicInvokeConstructorInstruction(DynamicInvokeConstructorInstruction inst) + { + return Default(inst); + } + protected internal virtual T VisitDynamicInvokeInstruction(DynamicInvokeInstruction inst) + { + return Default(inst); + } + protected internal virtual T VisitDynamicIsEventInstruction(DynamicIsEventInstruction inst) + { + return Default(inst); + } protected internal virtual T VisitMakeRefAny(MakeRefAny inst) { return Default(inst); @@ -5991,6 +7001,50 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst, context); } + protected internal virtual T VisitDynamicBinaryOperatorInstruction(DynamicBinaryOperatorInstruction inst, C context) + { + return Default(inst, context); + } + protected internal virtual T VisitDynamicUnaryOperatorInstruction(DynamicUnaryOperatorInstruction inst, C context) + { + return Default(inst, context); + } + protected internal virtual T VisitDynamicConvertInstruction(DynamicConvertInstruction inst, C context) + { + return Default(inst, context); + } + protected internal virtual T VisitDynamicGetMemberInstruction(DynamicGetMemberInstruction inst, C context) + { + return Default(inst, context); + } + protected internal virtual T VisitDynamicSetMemberInstruction(DynamicSetMemberInstruction inst, C context) + { + return Default(inst, context); + } + protected internal virtual T VisitDynamicGetIndexInstruction(DynamicGetIndexInstruction inst, C context) + { + return Default(inst, context); + } + protected internal virtual T VisitDynamicSetIndexInstruction(DynamicSetIndexInstruction inst, C context) + { + return Default(inst, context); + } + protected internal virtual T VisitDynamicInvokeMemberInstruction(DynamicInvokeMemberInstruction inst, C context) + { + return Default(inst, context); + } + protected internal virtual T VisitDynamicInvokeConstructorInstruction(DynamicInvokeConstructorInstruction inst, C context) + { + return Default(inst, context); + } + protected internal virtual T VisitDynamicInvokeInstruction(DynamicInvokeInstruction inst, C context) + { + return Default(inst, context); + } + protected internal virtual T VisitDynamicIsEventInstruction(DynamicIsEventInstruction inst, C context) + { + return Default(inst, context); + } protected internal virtual T VisitMakeRefAny(MakeRefAny inst, C context) { return Default(inst, context); @@ -6088,6 +7142,17 @@ namespace ICSharpCode.Decompiler.IL "array.to.pointer", "string.to.int", "expression.tree.cast", + "dynamic.binary.operator", + "dynamic.unary.operator", + "dynamic.convert", + "dynamic.getmember", + "dynamic.setmember", + "dynamic.getindex", + "dynamic.setindex", + "dynamic.invokemember", + "dynamic.invokeconstructor", + "dynamic.invoke", + "dynamic.isevent", "mkrefany", "refanytype", "refanyval", diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index 667369b9e..6f75055ff 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -33,6 +33,8 @@ new OpCode("CallInstruction", "Instruction with a list of arguments.", AbstractBaseClass, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomWriteTo, MayThrow, SideEffect), + new OpCode("DynamicInstruction", "Instruction representing a dynamic call site.", + AbstractBaseClass, CustomWriteTo, MayThrow, SideEffect), new OpCode("PatternInstruction", "Base class for pattern matching in ILAst.", AbstractBaseClass, ResultType("Unknown")) { Namespace = "ICSharpCode.Decompiler.IL.Patterns" } }; @@ -260,6 +262,30 @@ CustomClassName("ExpressionTreeCast"), Unary, HasTypeOperand, MayThrow, CustomConstructor, CustomWriteTo, ResultType("type.GetStackType()"), MatchCondition("this.IsChecked == o.IsChecked")), + new OpCode("dynamic.binary.operator", "ILAst representation of a binary operator inside a dynamic expression (maps to Binder.BinaryOperation).", + CustomClassName("DynamicBinaryOperatorInstruction"), BaseClass("DynamicInstruction"), CustomArguments(("left", null), ("right", null)), CustomConstructor, CustomWriteTo), + new OpCode("dynamic.unary.operator", "ILAst representation of a unary operator inside a dynamic expression (maps to Binder.UnaryOperation).", + CustomClassName("DynamicUnaryOperatorInstruction"), BaseClass("DynamicInstruction"), CustomArguments(("operand", null)), CustomConstructor, CustomWriteTo), + new OpCode("dynamic.convert", "ILAst representation of a cast inside a dynamic expression (maps to Binder.Convert).", + CustomClassName("DynamicConvertInstruction"), BaseClass("DynamicInstruction"), HasTypeOperand, MayThrow, CustomArguments(("argument", new[] { "O" })), CustomConstructor, CustomWriteTo), + new OpCode("dynamic.getmember", "ILAst representation of a property get method call inside a dynamic expression (maps to Binder.GetMember).", + CustomClassName("DynamicGetMemberInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomArguments(("target", new[] { "O" })), CustomConstructor, CustomWriteTo), + new OpCode("dynamic.setmember", "ILAst representation of a property set method call inside a dynamic expression (maps to Binder.SetMember).", + CustomClassName("DynamicSetMemberInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomArguments(("target", new[] { "O" }), ("value", null)), CustomConstructor, CustomWriteTo), + new OpCode("dynamic.getindex", "ILAst representation of an indexer get method call inside a dynamic expression (maps to Binder.GetIndex).", + CustomClassName("DynamicGetIndexInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomConstructor, CustomWriteTo), + new OpCode("dynamic.setindex", "ILAst representation of an indexer set method call inside a dynamic expression (maps to Binder.SetIndex).", + CustomClassName("DynamicSetIndexInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomConstructor, CustomWriteTo), + new OpCode("dynamic.invokemember", "ILAst representation of a method call inside a dynamic expression (maps to Binder.InvokeMember).", + CustomClassName("DynamicInvokeMemberInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomConstructor, CustomWriteTo), + new OpCode("dynamic.invokeconstructor", "ILAst representation of a constuctor invocation inside a dynamic expression (maps to Binder.InvokeConstructor).", + CustomClassName("DynamicInvokeConstructorInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomConstructor, CustomWriteTo), + new OpCode("dynamic.invoke", "ILAst representation of a delegate invocation inside a dynamic expression (maps to Binder.Invoke).", + CustomClassName("DynamicInvokeInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomChildren(new []{ new ArgumentInfo("arguments") { IsCollection = true }}), CustomConstructor, CustomWriteTo), + new OpCode("dynamic.isevent", "ILAst representation of a call to the Binder.IsEvent method inside a dynamic expression.", + CustomClassName("DynamicIsEventInstruction"), BaseClass("DynamicInstruction"), MayThrow, CustomArguments(("argument", new[] { "O" })), CustomConstructor, CustomWriteTo), + + new OpCode("mkrefany", "Push a typed reference of type class onto the stack.", CustomClassName("MakeRefAny"), Unary, HasTypeOperand, ResultType("O")), new OpCode("refanytype", "Push the type token stored in a typed reference.", diff --git a/ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs b/ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs new file mode 100644 index 000000000..9a9c65694 --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs @@ -0,0 +1,463 @@ +// Copyright (c) 2018 Siegfried Pammer +// +// 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.Linq.Expressions; +using System.Text; +using ICSharpCode.Decompiler.IL.Patterns; +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.Util; + +namespace ICSharpCode.Decompiler.IL +{ + [Flags] + public enum CSharpArgumentInfoFlags + { + None = 0, + UseCompileTimeType = 1, + Constant = 2, + NamedArgument = 4, + IsRef = 8, + IsOut = 0x10, + IsStaticType = 0x20 + } + + [Flags] + public enum CSharpBinderFlags + { + None = 0, + CheckedContext = 1, + InvokeSimpleName = 2, + InvokeSpecialName = 4, + BinaryOperationLogical = 8, + ConvertExplicit = 0x10, + ConvertArrayIndex = 0x20, + ResultIndexed = 0x40, + ValueFromCompoundAssignment = 0x80, + ResultDiscarded = 0x100 + } + + public struct CSharpArgumentInfo + { + public string Name { get; set; } + public CSharpArgumentInfoFlags Flags { get; set; } + } + + partial class DynamicInstruction + { + public CSharpBinderFlags BinderFlags { get; } + public IType CallingContext { get; } + + protected DynamicInstruction(OpCode opCode, CSharpBinderFlags binderFlags, IType context) + : base(opCode) + { + BinderFlags = binderFlags; + CallingContext = context; + } + + protected void WriteBinderFlags(ITextOutput output, ILAstWritingOptions options) + { + if ((BinderFlags & CSharpBinderFlags.BinaryOperationLogical) != 0) + output.Write(".logic"); + if ((BinderFlags & CSharpBinderFlags.CheckedContext) != 0) + output.Write(".checked"); + if ((BinderFlags & CSharpBinderFlags.ConvertArrayIndex) != 0) + output.Write(".arrayindex"); + if ((BinderFlags & CSharpBinderFlags.ConvertExplicit) != 0) + output.Write(".explicit"); + if ((BinderFlags & CSharpBinderFlags.InvokeSimpleName) != 0) + output.Write(".invokesimple"); + if ((BinderFlags & CSharpBinderFlags.InvokeSpecialName) != 0) + output.Write(".invokespecial"); + if ((BinderFlags & CSharpBinderFlags.ResultDiscarded) != 0) + output.Write(".discard"); + if ((BinderFlags & CSharpBinderFlags.ResultIndexed) != 0) + output.Write(".resultindexed"); + if ((BinderFlags & CSharpBinderFlags.ValueFromCompoundAssignment) != 0) + output.Write(".compound"); + } + } + + partial class DynamicConvertInstruction + { + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + WriteBinderFlags(output, options); + output.Write(' '); + type.WriteTo(output); + output.Write('('); + argument.WriteTo(output, options); + output.Write(')'); + } + + public DynamicConvertInstruction(CSharpBinderFlags binderFlags, IType type, IType context, ILInstruction argument) + : base(OpCode.DynamicConvertInstruction, binderFlags, context) + { + Type = type; + Argument = argument; + } + + protected internal override bool PerformMatch(ref ListMatch listMatch, ref Match match) + { + return base.PerformMatch(ref listMatch, ref match); + } + + public override StackType ResultType => type.GetStackType(); + + public bool IsChecked => (BinderFlags & CSharpBinderFlags.CheckedContext) != 0; + } + + partial class DynamicInvokeMemberInstruction + { + public string Name { get; } + public IReadOnlyList TypeArguments { get; } + public IReadOnlyList ArgumentInfo { get; } + + public DynamicInvokeMemberInstruction(CSharpBinderFlags binderFlags, string name, IType[] typeArguments, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments) + : base(OpCode.DynamicInvokeMemberInstruction, binderFlags, context) + { + Name = name; + TypeArguments = typeArguments ?? Empty.Array; + ArgumentInfo = argumentInfo; + Arguments = new InstructionCollection(this, 0); + Arguments.AddRange(arguments); + } + + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + WriteBinderFlags(output, options); + output.Write(' '); + output.Write(Name); + if (TypeArguments.Count > 0) { + output.Write('<'); + int i = 0; + foreach (var typeArg in TypeArguments) { + if (i > 0) + output.Write(", "); + typeArg.WriteTo(output); + i++; + } + output.Write('>'); + } + output.Write('('); + int j = 0; + foreach (var arg in Arguments) { + if (j > 0) + output.Write(", "); + arg.WriteTo(output, options); + j++; + } + output.Write(')'); + } + + public override StackType ResultType => SpecialType.Dynamic.GetStackType(); + } + + partial class DynamicGetMemberInstruction + { + public string Name { get; } + public CSharpArgumentInfo TargetArgumentInfo { get; } + + public DynamicGetMemberInstruction(CSharpBinderFlags binderFlags, string name, IType context, CSharpArgumentInfo targetArgumentInfo, ILInstruction target) + : base(OpCode.DynamicGetMemberInstruction, binderFlags, context) + { + Name = name; + TargetArgumentInfo = targetArgumentInfo; + Target = target; + } + + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + WriteBinderFlags(output, options); + output.Write(' '); + output.Write(Name); + output.Write('('); + Target.WriteTo(output, options); + output.Write(')'); + } + + public override StackType ResultType => SpecialType.Dynamic.GetStackType(); + } + + partial class DynamicSetMemberInstruction + { + public string Name { get; } + public CSharpArgumentInfo TargetArgumentInfo { get; } + public CSharpArgumentInfo ValueArgumentInfo { get; } + + public DynamicSetMemberInstruction(CSharpBinderFlags binderFlags, string name, IType context, CSharpArgumentInfo targetArgumentInfo, ILInstruction target, CSharpArgumentInfo valueArgumentInfo, ILInstruction value) + : base(OpCode.DynamicSetMemberInstruction, binderFlags, context) + { + Name = name; + TargetArgumentInfo = targetArgumentInfo; + Target = target; + ValueArgumentInfo = valueArgumentInfo; + Value = value; + } + + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + WriteBinderFlags(output, options); + output.Write(' '); + output.Write(Name); + output.Write('('); + Target.WriteTo(output, options); + output.Write(", "); + Value.WriteTo(output, options); + output.Write(')'); + } + + public override StackType ResultType => SpecialType.Dynamic.GetStackType(); + } + + partial class DynamicGetIndexInstruction + { + public IReadOnlyList ArgumentInfo { get; } + + public DynamicGetIndexInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments) + : base(OpCode.DynamicGetIndexInstruction, binderFlags, context) + { + ArgumentInfo = argumentInfo; + Arguments = new InstructionCollection(this, 0); + Arguments.AddRange(arguments); + } + + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + WriteBinderFlags(output, options); + output.Write(' '); + output.Write("get_Item"); + output.Write('('); + int j = 0; + foreach (var arg in Arguments) { + if (j > 0) + output.Write(", "); + arg.WriteTo(output, options); + j++; + } + output.Write(')'); + } + + public override StackType ResultType => SpecialType.Dynamic.GetStackType(); + } + + partial class DynamicSetIndexInstruction + { + public IReadOnlyList ArgumentInfo { get; } + + public DynamicSetIndexInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments) + : base(OpCode.DynamicSetIndexInstruction, binderFlags, context) + { + ArgumentInfo = argumentInfo; + Arguments = new InstructionCollection(this, 0); + Arguments.AddRange(arguments); + } + + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + WriteBinderFlags(output, options); + output.Write(' '); + output.Write("set_Item"); + output.Write('('); + int j = 0; + foreach (var arg in Arguments) { + if (j > 0) + output.Write(", "); + arg.WriteTo(output, options); + j++; + } + output.Write(')'); + } + + public override StackType ResultType => SpecialType.Dynamic.GetStackType(); + } + + partial class DynamicInvokeConstructorInstruction + { + public IReadOnlyList ArgumentInfo { get; } + + public DynamicInvokeConstructorInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments) + : base(OpCode.DynamicInvokeConstructorInstruction, binderFlags, context) + { + ArgumentInfo = argumentInfo; + Arguments = new InstructionCollection(this, 0); + Arguments.AddRange(arguments); + } + + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + WriteBinderFlags(output, options); + output.Write(' '); + output.Write(".ctor"); + output.Write('('); + int j = 0; + foreach (var arg in Arguments) { + if (j > 0) + output.Write(", "); + arg.WriteTo(output, options); + j++; + } + output.Write(')'); + } + + public override StackType ResultType => SpecialType.Dynamic.GetStackType(); + } + + partial class DynamicBinaryOperatorInstruction + { + public CSharpArgumentInfo LeftArgumentInfo { get; } + public CSharpArgumentInfo RightArgumentInfo { get; } + public ExpressionType Operation { get; } + + public DynamicBinaryOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType context, CSharpArgumentInfo leftArgumentInfo, ILInstruction left, CSharpArgumentInfo rightArgumentInfo, ILInstruction right) + : base(OpCode.DynamicBinaryOperatorInstruction, binderFlags, context) + { + Operation = operation; + LeftArgumentInfo = leftArgumentInfo; + Left = left; + RightArgumentInfo = rightArgumentInfo; + Right = right; + } + + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + WriteBinderFlags(output, options); + output.Write(' '); + output.Write(Operation.ToString()); + output.Write('('); + Left.WriteTo(output, options); + output.Write(", "); + Right.WriteTo(output, options); + output.Write(')'); + } + + public override StackType ResultType => SpecialType.Dynamic.GetStackType(); + } + + partial class DynamicUnaryOperatorInstruction + { + public CSharpArgumentInfo OperandArgumentInfo { get; } + public ExpressionType Operation { get; } + + public DynamicUnaryOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType context, CSharpArgumentInfo operandArgumentInfo, ILInstruction operand) + : base(OpCode.DynamicUnaryOperatorInstruction, binderFlags, context) + { + Operation = operation; + OperandArgumentInfo = operandArgumentInfo; + Operand = operand; + } + + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + WriteBinderFlags(output, options); + output.Write(' '); + output.Write(Operation.ToString()); + output.Write('('); + Operand.WriteTo(output, options); + output.Write(')'); + } + + public override StackType ResultType { + get { + switch (Operation) { + case ExpressionType.IsFalse: + case ExpressionType.IsTrue: + return StackType.I4; // bool + default: + return SpecialType.Dynamic.GetStackType(); + } + } + } + } + + partial class DynamicInvokeInstruction + { + public IReadOnlyList ArgumentInfo { get; } + + public DynamicInvokeInstruction(CSharpBinderFlags binderFlags, IType context, CSharpArgumentInfo[] argumentInfo, ILInstruction[] arguments) + : base(OpCode.DynamicInvokeInstruction, binderFlags, context) + { + ArgumentInfo = argumentInfo; + Arguments = new InstructionCollection(this, 0); + Arguments.AddRange(arguments); + } + + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + WriteBinderFlags(output, options); + output.Write(' '); + output.Write('('); + int j = 0; + foreach (var arg in Arguments) { + if (j > 0) + output.Write(", "); + arg.WriteTo(output, options); + j++; + } + output.Write(')'); + } + + public override StackType ResultType => SpecialType.Dynamic.GetStackType(); + } + + partial class DynamicIsEventInstruction + { + public string Name { get; } + + public DynamicIsEventInstruction(CSharpBinderFlags binderFlags, string name, IType context, ILInstruction argument) + : base(OpCode.DynamicIsEventInstruction, binderFlags, context) + { + Name = name; + Argument = argument; + } + + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + WriteBinderFlags(output, options); + output.Write(' '); + output.Write('('); + Argument.WriteTo(output, options); + output.Write(')'); + } + + public override StackType ResultType => StackType.I4; + } +} diff --git a/ICSharpCode.Decompiler/IL/Transforms/ExpressionTreeCast.cs b/ICSharpCode.Decompiler/IL/Instructions/ExpressionTreeCast.cs similarity index 100% rename from ICSharpCode.Decompiler/IL/Transforms/ExpressionTreeCast.cs rename to ICSharpCode.Decompiler/IL/Instructions/ExpressionTreeCast.cs