From 0bb71f469d0ab3a8ea8cfea5b6900ee917beb1e3 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 1 Jun 2018 20:14:22 +0200 Subject: [PATCH] Add DynamicCompoundAssign instruction --- ICSharpCode.Decompiler/IL/Instructions.cs | 89 ++++++++++++++----- ICSharpCode.Decompiler/IL/Instructions.tt | 6 ++ .../CompoundAssignmentInstruction.cs | 68 ++++++++++++++ .../IL/Instructions/DynamicInstructions.cs | 4 + 4 files changed, 147 insertions(+), 20 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index cefff257e..ab2b0fbe7 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -49,6 +49,8 @@ namespace ICSharpCode.Decompiler.IL NumericCompoundAssign, /// Common instruction for user-defined compound assignments. UserDefinedCompoundAssign, + /// Common instruction for dynamic compound assignments. + DynamicCompoundAssign, /// Bitwise NOT BitNot, /// Retrieves the RuntimeArgumentHandle. @@ -497,26 +499,6 @@ 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. @@ -619,6 +601,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 { /// Represents invalid IL. Semantically, this instruction is considered to throw some kind of exception. public sealed partial class InvalidBranch : SimpleInstruction @@ -1089,6 +1091,40 @@ namespace ICSharpCode.Decompiler.IL } } namespace ICSharpCode.Decompiler.IL +{ + /// Common instruction for dynamic compound assignments. + public sealed partial class DynamicCompoundAssign : CompoundAssignmentInstruction + { + public override StackType ResultType { get { return StackType.O; } } + protected override InstructionFlags ComputeFlags() + { + return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.SideEffect; + } + public override InstructionFlags DirectFlags { + get { + return base.DirectFlags | InstructionFlags.MayThrow | InstructionFlags.SideEffect; + } + } + public override void AcceptVisitor(ILVisitor visitor) + { + visitor.VisitDynamicCompoundAssign(this); + } + public override T AcceptVisitor(ILVisitor visitor) + { + return visitor.VisitDynamicCompoundAssign(this); + } + public override T AcceptVisitor(ILVisitor visitor, C context) + { + return visitor.VisitDynamicCompoundAssign(this, context); + } + protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) + { + var o = other as DynamicCompoundAssign; + return o != null && this.CompoundAssignmentType == o.CompoundAssignmentType && Target.PerformMatch(o.Target, ref match) && Value.PerformMatch(o.Value, ref match); + } + } +} +namespace ICSharpCode.Decompiler.IL { /// Bitwise NOT public sealed partial class BitNot : UnaryInstruction @@ -6091,6 +6127,10 @@ namespace ICSharpCode.Decompiler.IL { Default(inst); } + protected internal virtual void VisitDynamicCompoundAssign(DynamicCompoundAssign inst) + { + Default(inst); + } protected internal virtual void VisitBitNot(BitNot inst) { Default(inst); @@ -6457,6 +6497,10 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst); } + protected internal virtual T VisitDynamicCompoundAssign(DynamicCompoundAssign inst) + { + return Default(inst); + } protected internal virtual T VisitBitNot(BitNot inst) { return Default(inst); @@ -6823,6 +6867,10 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst, context); } + protected internal virtual T VisitDynamicCompoundAssign(DynamicCompoundAssign inst, C context) + { + return Default(inst, context); + } protected internal virtual T VisitBitNot(BitNot inst, C context) { return Default(inst, context); @@ -7154,6 +7202,7 @@ namespace ICSharpCode.Decompiler.IL "binary", "numeric.compound", "user.compound", + "dynamic.compound", "bit.not", "arglist", "br", diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index a5d031b43..8e36f1bce 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -83,6 +83,12 @@ MatchCondition("this.CompoundAssignmentType == o.CompoundAssignmentType"), MatchCondition("Target.PerformMatch(o.Target, ref match)"), MatchCondition("Value.PerformMatch(o.Value, ref match)")), + new OpCode("dynamic.compound", "Common instruction for dynamic compound assignments.", + CustomClassName("DynamicCompoundAssign"), BaseClass("CompoundAssignmentInstruction"), CustomConstructor, + MayThrow, SideEffect, CustomWriteTo, ResultType("O"), + MatchCondition("this.CompoundAssignmentType == o.CompoundAssignmentType"), + MatchCondition("Target.PerformMatch(o.Target, ref match)"), + MatchCondition("Value.PerformMatch(o.Value, ref match)")), new OpCode("bit.not", "Bitwise NOT", Unary, CustomConstructor, MatchCondition("IsLifted == o.IsLifted && UnderlyingResultType == o.UnderlyingResultType")), new OpCode("arglist", "Retrieves the RuntimeArgumentHandle.", NoArguments, ResultType("O")), new OpCode("br", "Unconditional branch. goto target;", diff --git a/ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs index 1c9753620..687d6daf0 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs @@ -18,6 +18,7 @@ using System; using System.Diagnostics; +using System.Linq.Expressions; using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.Decompiler.IL @@ -212,6 +213,7 @@ namespace ICSharpCode.Decompiler.IL { ILRange.WriteTo(output, options); output.Write(OpCode); + if (CompoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue) output.Write(".new"); else @@ -225,6 +227,72 @@ namespace ICSharpCode.Decompiler.IL output.Write(')'); } } + + public partial class DynamicCompoundAssign : CompoundAssignmentInstruction + { + public ExpressionType Operation { get; } + public CSharpArgumentInfo TargetArgumentInfo { get; } + public CSharpArgumentInfo ValueArgumentInfo { get; } + + public DynamicCompoundAssign(ExpressionType op, ILInstruction target, CSharpArgumentInfo targetArgumentInfo, ILInstruction value, CSharpArgumentInfo valueArgumentInfo) + : base(OpCode.DynamicCompoundAssign, CompoundAssignmentTypeFromOperation(op), target, value) + { + if (!IsExpressionTypeSupported(op)) + throw new ArgumentOutOfRangeException("op"); + this.Operation = op; + this.TargetArgumentInfo = targetArgumentInfo; + this.ValueArgumentInfo = valueArgumentInfo; + } + + public override void WriteTo(ITextOutput output, ILAstWritingOptions options) + { + ILRange.WriteTo(output, options); + output.Write(OpCode); + output.Write("." + Operation.ToString().ToLower()); + if (CompoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue) + output.Write(".new"); + else + output.Write(".old"); + output.Write(' '); + output.Write('('); + this.Target.WriteTo(output, options); + output.Write(", "); + this.Value.WriteTo(output, options); + output.Write(')'); + } + + internal static bool IsExpressionTypeSupported(ExpressionType type) + { + return type == ExpressionType.AddAssign + || type == ExpressionType.AddAssignChecked + || type == ExpressionType.AndAssign + || type == ExpressionType.DivideAssign + || type == ExpressionType.ExclusiveOrAssign + || type == ExpressionType.LeftShiftAssign + || type == ExpressionType.ModuloAssign + || type == ExpressionType.MultiplyAssign + || type == ExpressionType.MultiplyAssignChecked + || type == ExpressionType.OrAssign + || type == ExpressionType.PostDecrementAssign + || type == ExpressionType.PostIncrementAssign + || type == ExpressionType.PreDecrementAssign + || type == ExpressionType.PreIncrementAssign + || type == ExpressionType.RightShiftAssign + || type == ExpressionType.SubtractAssign + || type == ExpressionType.SubtractAssignChecked; + } + + static CompoundAssignmentType CompoundAssignmentTypeFromOperation(ExpressionType op) + { + switch (op) { + case ExpressionType.PostIncrementAssign: + case ExpressionType.PostDecrementAssign: + return CompoundAssignmentType.EvaluatesToOldValue; + default: + return CompoundAssignmentType.EvaluatesToNewValue; + } + } + } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs b/ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs index 9a9c65694..263cd86ff 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs @@ -57,6 +57,7 @@ namespace ICSharpCode.Decompiler.IL { public string Name { get; set; } public CSharpArgumentInfoFlags Flags { get; set; } + public IType CompileTimeType { get; set; } } partial class DynamicInstruction @@ -164,6 +165,9 @@ namespace ICSharpCode.Decompiler.IL foreach (var arg in Arguments) { if (j > 0) output.Write(", "); + output.Write("[flags: "); + output.Write(ArgumentInfo[j].Flags.ToString()); + output.Write(", name: " + ArgumentInfo[j].Name + "] "); arg.WriteTo(output, options); j++; }