diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 5f762dd2e..2109bad73 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -1063,25 +1063,25 @@ namespace ICSharpCode.Decompiler.CSharp return Assignment(result, value).WithILInstruction(inst); } - protected internal override TranslatedExpression VisitLdFld(LdFld inst) - { - return ConvertField(inst.Field, inst.Target).WithILInstruction(inst); - } - - protected internal override TranslatedExpression VisitStFld(StFld inst) - { - return Assignment(ConvertField(inst.Field, inst.Target).WithoutILInstruction(), Translate(inst.Value)).WithILInstruction(inst); - } - - protected internal override TranslatedExpression VisitLdsFld(LdsFld inst) - { - return ConvertField(inst.Field).WithILInstruction(inst); - } - - protected internal override TranslatedExpression VisitStsFld(StsFld inst) - { - return Assignment(ConvertField(inst.Field).WithoutILInstruction(), Translate(inst.Value)).WithILInstruction(inst); - } +// protected internal override TranslatedExpression VisitLdFld(LdFld inst) +// { +// return ConvertField(inst.Field, inst.Target).WithILInstruction(inst); +// } +// +// protected internal override TranslatedExpression VisitStFld(StFld inst) +// { +// return Assignment(ConvertField(inst.Field, inst.Target).WithoutILInstruction(), Translate(inst.Value)).WithILInstruction(inst); +// } +// +// protected internal override TranslatedExpression VisitLdsFld(LdsFld inst) +// { +// return ConvertField(inst.Field).WithILInstruction(inst); +// } +// +// protected internal override TranslatedExpression VisitStsFld(StsFld inst) +// { +// return Assignment(ConvertField(inst.Field).WithoutILInstruction(), Translate(inst.Value)).WithILInstruction(inst); +// } protected internal override TranslatedExpression VisitLdLen(LdLen inst) { diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index cfa1a8578..e4bf3d963 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -720,26 +720,32 @@ namespace ICSharpCode.Decompiler.IL case ILOpCode.Ldelema: return Push(new LdElema(indices: Pop(), array: Pop(), type: ReadAndDecodeTypeReference())); case ILOpCode.Ldfld: - return Push(new LdFld(Pop(), ReadAndDecodeFieldReference())); + { + var field = ReadAndDecodeFieldReference(); + return Push(new LdObj(new LdFlda(Pop(), field) { DelayExceptions = true }, field.Type)); + } case ILOpCode.Ldflda: return Push(new LdFlda(Pop(), ReadAndDecodeFieldReference())); case ILOpCode.Stfld: { var field = ReadAndDecodeFieldReference(); - return new StFld(value: Pop(field.Type.GetStackType()), target: Pop(), field: field); + return new StObj(value: Pop(field.Type.GetStackType()), target: new LdFlda(Pop(), field) { DelayExceptions = true }, type: field.Type); } case ILOpCode.Ldlen: return Push(new LdLen(StackType.I, Pop())); case ILOpCode.Ldobj: return Push(new LdObj(PopPointer(), ReadAndDecodeTypeReference())); case ILOpCode.Ldsfld: - return Push(new LdsFld(ReadAndDecodeFieldReference())); + { + var field = ReadAndDecodeFieldReference(); + return Push(new LdObj(new LdsFlda(field), field.Type)); + } case ILOpCode.Ldsflda: return Push(new LdsFlda(ReadAndDecodeFieldReference())); case ILOpCode.Stsfld: { var field = ReadAndDecodeFieldReference(); - return new StsFld(Pop(field.Type.GetStackType()), field); + return new StObj(value: Pop(field.Type.GetStackType()), target: new LdsFlda(field), type: field.Type); } case ILOpCode.Ldtoken: return Push(LdToken(ReadAndDecodeMetadataToken())); diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index c7e8cb131..23715522b 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -129,18 +129,10 @@ namespace ICSharpCode.Decompiler.IL 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. @@ -2027,101 +2019,6 @@ namespace ICSharpCode.Decompiler.IL } } - /// Load instance field - public sealed partial class LdFld : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix, IInstructionWithFieldOperand - { - public LdFld(ILInstruction target, IField field) : base(OpCode.LdFld) - { - this.Target = target; - this.field = field; - } - public static readonly SlotInfo TargetSlot = new SlotInfo("Target", canInlineInto: true); - ILInstruction target; - public ILInstruction Target { - get { return this.target; } - set { - ValidateChild(value); - SetChildInstruction(ref this.target, value, 0); - } - } - protected sealed override int GetChildCount() - { - return 1; - } - protected sealed override ILInstruction GetChild(int index) - { - switch (index) { - case 0: - return this.target; - default: - throw new IndexOutOfRangeException(); - } - } - protected sealed override void SetChild(int index, ILInstruction value) - { - switch (index) { - case 0: - this.Target = value; - break; - default: - throw new IndexOutOfRangeException(); - } - } - protected sealed override SlotInfo GetChildSlot(int index) - { - switch (index) { - case 0: - return TargetSlot; - default: - throw new IndexOutOfRangeException(); - } - } - public sealed override ILInstruction Clone() - { - var clone = (LdFld)ShallowClone(); - clone.Target = this.target.Clone(); - return clone; - } - /// 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 IField field; - /// Returns the field operand. - public IField Field { get { return field; } } - public override StackType ResultType { get { return field.Type.GetStackType(); } } - protected override InstructionFlags ComputeFlags() - { - return target.Flags | InstructionFlags.SideEffect | InstructionFlags.MayThrow; - } - public override InstructionFlags DirectFlags { - get { - return InstructionFlags.SideEffect | InstructionFlags.MayThrow; - } - } - public override void WriteTo(ITextOutput output) - { - if (IsVolatile) - output.Write("volatile."); - if (UnalignedPrefix > 0) - output.Write("unaligned(" + UnalignedPrefix + ")."); - output.Write(OpCode); - output.Write(' '); - Disassembler.DisassemblerHelpers.WriteOperand(output, field); - output.Write('('); - this.target.WriteTo(output); - output.Write(')'); - } - public override void AcceptVisitor(ILVisitor visitor) - { - visitor.VisitLdFld(this); - } - public override T AcceptVisitor(ILVisitor visitor) - { - return visitor.VisitLdFld(this); - } - } - /// Load address of instance field public sealed partial class LdFlda : ILInstruction, IInstructionWithFieldOperand { @@ -2210,165 +2107,6 @@ namespace ICSharpCode.Decompiler.IL } } - /// Store value to instance field - public sealed partial class StFld : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix, IInstructionWithFieldOperand - { - public StFld(ILInstruction target, ILInstruction value, IField field) : base(OpCode.StFld) - { - this.Target = target; - this.Value = value; - this.field = field; - } - public static readonly SlotInfo TargetSlot = new SlotInfo("Target", canInlineInto: true); - ILInstruction target; - public ILInstruction Target { - get { return this.target; } - set { - ValidateChild(value); - SetChildInstruction(ref this.target, value, 0); - } - } - 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 = (StFld)ShallowClone(); - clone.Target = this.target.Clone(); - clone.Value = this.value.Clone(); - return clone; - } - /// 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 IField field; - /// Returns the field operand. - public IField Field { get { return field; } } - public override StackType ResultType { get { return field.Type.GetStackType(); } } - protected override InstructionFlags ComputeFlags() - { - return target.Flags | value.Flags | InstructionFlags.SideEffect | InstructionFlags.MayThrow; - } - public override InstructionFlags DirectFlags { - get { - return InstructionFlags.SideEffect | InstructionFlags.MayThrow; - } - } - public override void WriteTo(ITextOutput output) - { - if (IsVolatile) - output.Write("volatile."); - if (UnalignedPrefix > 0) - output.Write("unaligned(" + UnalignedPrefix + ")."); - output.Write(OpCode); - output.Write(' '); - Disassembler.DisassemblerHelpers.WriteOperand(output, field); - output.Write('('); - this.target.WriteTo(output); - output.Write(", "); - this.value.WriteTo(output); - output.Write(')'); - } - public override void AcceptVisitor(ILVisitor visitor) - { - visitor.VisitStFld(this); - } - public override T AcceptVisitor(ILVisitor visitor) - { - return visitor.VisitStFld(this); - } - } - - /// Load static field - public sealed partial class LdsFld : SimpleInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix, IInstructionWithFieldOperand - { - public LdsFld(IField 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 IField field; - /// Returns the field operand. - public IField Field { get { return field; } } - public override StackType ResultType { get { return field.Type.GetStackType(); } } - protected override InstructionFlags ComputeFlags() - { - return InstructionFlags.SideEffect; - } - public override InstructionFlags DirectFlags { - get { - 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 void AcceptVisitor(ILVisitor visitor) - { - visitor.VisitLdsFld(this); - } - public override T AcceptVisitor(ILVisitor visitor) - { - return visitor.VisitLdsFld(this); - } - } - /// Load static field address public sealed partial class LdsFlda : SimpleInstruction, IInstructionWithFieldOperand { @@ -2396,101 +2134,6 @@ namespace ICSharpCode.Decompiler.IL } } - /// Store value to static field - public sealed partial class StsFld : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix, IInstructionWithFieldOperand - { - public StsFld(ILInstruction value, IField field) : base(OpCode.StsFld) - { - this.Value = value; - this.field = field; - } - 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 = (StsFld)ShallowClone(); - clone.Value = this.value.Clone(); - return clone; - } - /// 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 IField field; - /// Returns the field operand. - public IField Field { get { return field; } } - public override StackType ResultType { get { return field.Type.GetStackType(); } } - protected override InstructionFlags ComputeFlags() - { - return value.Flags | InstructionFlags.SideEffect; - } - public override InstructionFlags DirectFlags { - get { - 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); - output.Write('('); - this.value.WriteTo(output); - output.Write(')'); - } - public override void AcceptVisitor(ILVisitor visitor) - { - visitor.VisitStsFld(this); - } - public override T AcceptVisitor(ILVisitor visitor) - { - return visitor.VisitStsFld(this); - } - } - /// Casts an object to a class. public sealed partial class CastClass : UnaryInstruction { @@ -3639,30 +3282,14 @@ namespace ICSharpCode.Decompiler.IL { Default(inst); } - protected internal virtual void VisitLdFld(LdFld inst) - { - Default(inst); - } protected internal virtual void VisitLdFlda(LdFlda inst) { Default(inst); } - protected internal virtual void VisitStFld(StFld inst) - { - Default(inst); - } - protected internal virtual void VisitLdsFld(LdsFld inst) - { - Default(inst); - } protected internal virtual void VisitLdsFlda(LdsFlda inst) { Default(inst); } - protected internal virtual void VisitStsFld(StsFld inst) - { - Default(inst); - } protected internal virtual void VisitCastClass(CastClass inst) { Default(inst); @@ -3949,30 +3576,14 @@ namespace ICSharpCode.Decompiler.IL { 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); @@ -4146,12 +3757,8 @@ namespace ICSharpCode.Decompiler.IL "ret", "shl", "shr", - "ldfld", "ldflda", - "stfld", - "ldsfld", "ldsflda", - "stsfld", "castclass", "isinst", "ldobj", @@ -4538,18 +4145,6 @@ namespace ICSharpCode.Decompiler.IL right = default(ILInstruction); return false; } - public bool MatchLdFld(out ILInstruction target, out IField field) - { - var inst = this as LdFld; - if (inst != null) { - target = inst.Target; - field = inst.Field; - return true; - } - target = default(ILInstruction); - field = default(IField); - return false; - } public bool MatchLdFlda(out ILInstruction target, out IField field) { var inst = this as LdFlda; @@ -4562,30 +4157,6 @@ namespace ICSharpCode.Decompiler.IL field = default(IField); return false; } - public bool MatchStFld(out ILInstruction target, out ILInstruction value, out IField field) - { - var inst = this as StFld; - if (inst != null) { - target = inst.Target; - value = inst.Value; - field = inst.Field; - return true; - } - target = default(ILInstruction); - value = default(ILInstruction); - field = default(IField); - return false; - } - public bool MatchLdsFld(out IField field) - { - var inst = this as LdsFld; - if (inst != null) { - field = inst.Field; - return true; - } - field = default(IField); - return false; - } public bool MatchLdsFlda(out IField field) { var inst = this as LdsFlda; @@ -4596,18 +4167,6 @@ namespace ICSharpCode.Decompiler.IL field = default(IField); return false; } - public bool MatchStsFld(out ILInstruction value, out IField field) - { - var inst = this as StsFld; - if (inst != null) { - value = inst.Value; - field = inst.Field; - return true; - } - value = default(ILInstruction); - field = default(IField); - return false; - } public bool MatchCastClass(out ILInstruction argument, out IType type) { var inst = this as CastClass; diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index 15e50b638..8f745e076 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -146,24 +146,10 @@ new OpCode("shl", "Shift left", BinaryNumeric), new OpCode("shr", "Shift right", BinaryNumeric), - new OpCode("ldfld", "Load instance field", - CustomClassName("LdFld"), CustomArguments("target"), MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, - HasFieldOperand, ResultType("field.Type.GetStackType()")), new OpCode("ldflda", "Load address of instance field", CustomClassName("LdFlda"), CustomArguments("target"), MayThrowIfNotDelayed, HasFieldOperand, ResultType("Ref")), - new OpCode("stfld", "Store value to instance field", - CustomClassName("StFld"), CustomArguments("target", "value"), - MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, HasFieldOperand, - ResultType("field.Type.GetStackType()")), - new OpCode("ldsfld", "Load static field", - CustomClassName("LdsFld"), NoArguments, MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, - HasFieldOperand, ResultType("field.Type.GetStackType()")), new OpCode("ldsflda", "Load static field address", CustomClassName("LdsFlda"), NoArguments, ResultType("Ref"), HasFieldOperand), - new OpCode("stsfld", "Store value to static field", - CustomClassName("StsFld"), CustomArguments("value"), - MemoryAccess, SupportsVolatilePrefix, SupportsUnalignedPrefix, HasFieldOperand, - ResultType("field.Type.GetStackType()")), new OpCode("castclass", "Casts an object to a class.", CustomClassName("CastClass"), Unary, HasTypeOperand, MayThrow, ResultType("type.GetStackType()")), diff --git a/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs index 42eab1d86..9be3a53c8 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs @@ -61,8 +61,6 @@ namespace ICSharpCode.Decompiler.IL { switch (inst.OpCode) { case OpCode.LdLoc: - case OpCode.LdFld: - case OpCode.LdsFld: case OpCode.LdObj: return true; case OpCode.Call: diff --git a/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs b/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs index 22a57fddb..128b525da 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.Decompiler.IL { @@ -167,6 +168,40 @@ namespace ICSharpCode.Decompiler.IL return false; } + public bool MatchLdsFld(IField field) + { + LdsFlda ldsflda = (this as LdObj)?.Target as LdsFlda; + if (ldsflda != null) { + return field.Equals(ldsflda.Field); + } + return false; + } + + public bool MatchLdsFld(out IField field) + { + LdsFlda ldsflda = (this as LdObj)?.Target as LdsFlda; + if (ldsflda != null) { + field = ldsflda.Field; + return true; + } + field = null; + return false; + } + + public bool MatchStsFld(out ILInstruction value, out IField field) + { + var stobj = this as StObj; + LdsFlda ldsflda = stobj?.Target as LdsFlda; + if (ldsflda != null) { + value = stobj.Value; + field = ldsflda.Field; + return true; + } + value = null; + field = null; + return false; + } + /// /// If this instruction is a conversion of the specified kind, return its argument. /// Otherwise, return the instruction itself. diff --git a/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs b/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs index b38bb6a96..3e1a66b58 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs @@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms } block.Instructions.RemoveAt(i); int c = new ILInlining().InlineInto(block, i, aggressive: false); - i -= uninlinedArgs.Length + c + 1; + i -= c + 1; } } } @@ -73,8 +73,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms { switch (value.OpCode) { case OpCode.LdLoca: - case OpCode.LdElema: - case OpCode.LdFlda: +// case OpCode.LdElema: +// case OpCode.LdFlda: case OpCode.LdsFlda: // All address-loading instructions always return the same value for a given operand/argument combination, // so they can be safely copied. diff --git a/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs index 06dc621c9..1e9ee239f 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs @@ -170,7 +170,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms var nextInstruction = inst.Parent.Children.ElementAtOrDefault(inst.ChildIndex + 1); if (nextInstruction == null) return false; - var usages = nextInstruction.Descendants.OfType().Where(i => i.Field.Equals(field)).ToArray(); + var usages = nextInstruction.Descendants.Where(i => i.MatchLdsFld(field)).ToArray(); if (usages.Length != 1) return false; usages[0].ReplaceWith(value); diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs index 631759e11..4e6e2cf66 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs @@ -192,17 +192,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms switch (inlinedExpression.OpCode) { case OpCode.LdLoc: case OpCode.StLoc: - case OpCode.LdElema: return false; - case OpCode.LdFld: - case OpCode.StFld: - case OpCode.LdsFld: - case OpCode.StsFld: + case OpCode.LdObj: // allow inlining field access only if it's a readonly field - IField f = ((IInstructionWithFieldOperand)inlinedExpression).Field; - if (!f.IsReadOnly) - return false; - break; + IField f = (((LdObj)inlinedExpression).Target as IInstructionWithFieldOperand)?.Field; + if (f != null && f.IsReadOnly) + return true; + return f != null && f.IsReadOnly; case OpCode.Call: var m = ((CallInstruction)inlinedExpression).Method; // ensure that it's not an multi-dimensional array getter @@ -233,8 +229,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms return !((Call)parent).Method.IsStatic; case OpCode.CallVirt: return !((CallVirt)parent).Method.IsStatic; - case OpCode.StFld: - case OpCode.LdFld: case OpCode.LdFlda: // TODO : Reimplement Await //case OpCode.Await: diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformInlineAssignment.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformInlineAssignment.cs index 2c7366642..96a858d54 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/TransformInlineAssignment.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/TransformInlineAssignment.cs @@ -36,20 +36,52 @@ namespace ICSharpCode.Decompiler.IL.Transforms this.context = context; foreach (var block in function.Descendants.OfType()) { for (int i = block.Instructions.Count - 1; i >= 0; i--) { - var inst = block.Instructions[i] as StLoc; - var nextInst = block.Instructions.ElementAtOrDefault(i + 1) as StLoc; - ILVariable localVariable; - // stloc s(value) - // stloc l(ldloc s) - // --> - // stloc s(stloc l(value)) - if (inst != null && nextInst != null && nextInst.Variable.Kind != VariableKind.StackSlot && nextInst.Value.MatchLdLoc(inst.Variable)) { - block.Instructions.RemoveAt(i + 1); - var value = inst.Value.Clone(); - inst.Value.ReplaceWith(new StLoc(nextInst.Variable, value)); - } + TransformInlineAssignmentFields(block, i); + TransformInlineAssignmentLocal(block, i); } } } + + /// + /// stloc s(value) + /// stloc l(ldloc s) + /// --> + /// stloc s(stloc l(value)) + /// + static void TransformInlineAssignmentLocal(Block block, int i) + { + var inst = block.Instructions[i] as StLoc; + var nextInst = block.Instructions.ElementAtOrDefault(i + 1) as StLoc; + if (inst == null || nextInst == null) + return; + if (nextInst.Variable.Kind == VariableKind.StackSlot || !nextInst.Value.MatchLdLoc(inst.Variable)) + return; + block.Instructions.RemoveAt(i + 1); + var value = inst.Value.Clone(); + inst.Value.ReplaceWith(new StLoc(nextInst.Variable, value)); + } + + /// + /// stloc s(value) + /// stloc l(ldloc s) + /// stfld f(..., ldloc s) + /// --> + /// stloc l(stfld f(..., value)) + /// + static void TransformInlineAssignmentFields(Block block, int i) + { +// var inst = block.Instructions[i] as StLoc; +// var nextInst = block.Instructions.ElementAtOrDefault(i + 1) as StLoc; +// var fieldStore = block.Instructions.ElementAtOrDefault(i + 2) as StObj; +// if (inst == null || nextInst == null || fieldStore == null) +// return; +// if (nextInst.Variable.Kind == VariableKind.StackSlot || !nextInst.Value.MatchLdLoc(inst.Variable) || !fieldStore.Value.MatchLdLoc(inst.Variable)) +// return; +// var value = inst.Value.Clone(); +// var locVar = nextInst.Variable; +// block.Instructions.RemoveAt(i + 1); +// block.Instructions.RemoveAt(i + 1); +// inst.ReplaceWith(new StLoc(locVar, new StObj(fieldStore.Target, value, fieldStore.Field))); + } } } diff --git a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.cs b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.cs index f12f9b289..40ae049ab 100644 --- a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.cs +++ b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.cs @@ -22,6 +22,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { public class InlineAssignmentTest { + private int field1; + private InlineAssignmentTest field2; + public static void Main() { @@ -36,5 +39,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty Console.WriteLine((object)(V_1 = new InlineAssignmentTest())); Console.WriteLine((object)V_1); } + + public void SimpleInlineWithFields() + { + Console.WriteLine(this.field1 = 5); + Console.WriteLine((object)(this.field2 = new InlineAssignmentTest())); + } + + public void SimpleInlineWithFields2() + { + Console.WriteLine(this.field1 = 5); + Console.WriteLine(this.field1); + Console.WriteLine((object)(this.field2 = new InlineAssignmentTest())); + Console.WriteLine((object)this.field2); + } } } diff --git a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.il b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.il index f437b793d..580d0b79c 100644 --- a/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.il +++ b/ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.il @@ -10,7 +10,7 @@ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 4:0:0:0 } -.assembly '3cbicayo' +.assembly '3z5tjxm2' { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx @@ -20,15 +20,15 @@ .hash algorithm 0x00008004 .ver 0:0:0:0 } -.module '3cbicayo.exe' -// MVID: {3A96AD80-B3A9-47A7-82A9-A9BE249D0492} +.module '3z5tjxm2.exe' +// MVID: {3B1EB063-50AF-4CD4-83C3-9D26A66D9510} .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .imagebase 0x00400000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x01100000 +// Image base: 0x011D0000 // =============== CLASS MEMBERS DECLARATION =================== @@ -36,6 +36,8 @@ .class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest extends [mscorlib]System.Object { + .field private int32 field1 + .field private class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest field2 .method public hidebysig static void Main() cil managed { .entrypoint @@ -72,6 +74,68 @@ IL_0025: ret } // end of method InlineAssignmentTest::SimpleInlineWithLocals + .method public hidebysig instance void + SimpleInlineWithFields() cil managed + { + // Code size 38 (0x26) + .maxstack 3 + .locals init (int32 V_0, + class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.5 + IL_0003: dup + IL_0004: stloc.0 + IL_0005: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field1 + IL_000a: ldloc.0 + IL_000b: call void [mscorlib]System.Console::WriteLine(int32) + IL_0010: nop + IL_0011: ldarg.0 + IL_0012: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::.ctor() + IL_0017: dup + IL_0018: stloc.1 + IL_0019: stfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field2 + IL_001e: ldloc.1 + IL_001f: call void [mscorlib]System.Console::WriteLine(object) + IL_0024: nop + IL_0025: ret + } // end of method InlineAssignmentTest::SimpleInlineWithFields + + .method public hidebysig instance void + SimpleInlineWithFields2() cil managed + { + // Code size 62 (0x3e) + .maxstack 3 + .locals init (int32 V_0, + class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.5 + IL_0003: dup + IL_0004: stloc.0 + IL_0005: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field1 + IL_000a: ldloc.0 + IL_000b: call void [mscorlib]System.Console::WriteLine(int32) + IL_0010: nop + IL_0011: ldarg.0 + IL_0012: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field1 + IL_0017: call void [mscorlib]System.Console::WriteLine(int32) + IL_001c: nop + IL_001d: ldarg.0 + IL_001e: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::.ctor() + IL_0023: dup + IL_0024: stloc.1 + IL_0025: stfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field2 + IL_002a: ldloc.1 + IL_002b: call void [mscorlib]System.Console::WriteLine(object) + IL_0030: nop + IL_0031: ldarg.0 + IL_0032: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field2 + IL_0037: call void [mscorlib]System.Console::WriteLine(object) + IL_003c: nop + IL_003d: ret + } // end of method InlineAssignmentTest::SimpleInlineWithFields2 + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed {