Browse Source

Remove ld(s)fld/st(s)fld

pull/734/head
Siegfried Pammer 9 years ago
parent
commit
8766783eb6
  1. 38
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 14
      ICSharpCode.Decompiler/IL/ILReader.cs
  3. 441
      ICSharpCode.Decompiler/IL/Instructions.cs
  4. 14
      ICSharpCode.Decompiler/IL/Instructions.tt
  5. 2
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  6. 35
      ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs
  7. 6
      ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs
  8. 2
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs
  9. 16
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  10. 56
      ICSharpCode.Decompiler/IL/Transforms/TransformInlineAssignment.cs
  11. 17
      ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.cs
  12. 72
      ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.il

38
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1063,25 +1063,25 @@ namespace ICSharpCode.Decompiler.CSharp @@ -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)
{

14
ICSharpCode.Decompiler/IL/ILReader.cs

@ -720,26 +720,32 @@ namespace ICSharpCode.Decompiler.IL @@ -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()));

441
ICSharpCode.Decompiler/IL/Instructions.cs

@ -129,18 +129,10 @@ namespace ICSharpCode.Decompiler.IL @@ -129,18 +129,10 @@ namespace ICSharpCode.Decompiler.IL
Shl,
/// <summary>Shift right</summary>
Shr,
/// <summary>Load instance field</summary>
LdFld,
/// <summary>Load address of instance field</summary>
LdFlda,
/// <summary>Store value to instance field</summary>
StFld,
/// <summary>Load static field</summary>
LdsFld,
/// <summary>Load static field address</summary>
LdsFlda,
/// <summary>Store value to static field</summary>
StsFld,
/// <summary>Casts an object to a class.</summary>
CastClass,
/// <summary>Test if object is instance of class or interface.</summary>
@ -2027,101 +2019,6 @@ namespace ICSharpCode.Decompiler.IL @@ -2027,101 +2019,6 @@ namespace ICSharpCode.Decompiler.IL
}
}
/// <summary>Load instance field</summary>
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;
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; }
readonly IField field;
/// <summary>Returns the field operand.</summary>
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<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdFld(this);
}
}
/// <summary>Load address of instance field</summary>
public sealed partial class LdFlda : ILInstruction, IInstructionWithFieldOperand
{
@ -2210,165 +2107,6 @@ namespace ICSharpCode.Decompiler.IL @@ -2210,165 +2107,6 @@ namespace ICSharpCode.Decompiler.IL
}
}
/// <summary>Store value to instance field</summary>
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;
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; }
readonly IField field;
/// <summary>Returns the field operand.</summary>
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<T>(ILVisitor<T> visitor)
{
return visitor.VisitStFld(this);
}
}
/// <summary>Load static field</summary>
public sealed partial class LdsFld : SimpleInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix, IInstructionWithFieldOperand
{
public LdsFld(IField field) : base(OpCode.LdsFld)
{
this.field = field;
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; }
readonly IField field;
/// <summary>Returns the field operand.</summary>
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<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdsFld(this);
}
}
/// <summary>Load static field address</summary>
public sealed partial class LdsFlda : SimpleInstruction, IInstructionWithFieldOperand
{
@ -2396,101 +2134,6 @@ namespace ICSharpCode.Decompiler.IL @@ -2396,101 +2134,6 @@ namespace ICSharpCode.Decompiler.IL
}
}
/// <summary>Store value to static field</summary>
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;
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; }
readonly IField field;
/// <summary>Returns the field operand.</summary>
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<T>(ILVisitor<T> visitor)
{
return visitor.VisitStsFld(this);
}
}
/// <summary>Casts an object to a class.</summary>
public sealed partial class CastClass : UnaryInstruction
{
@ -3639,30 +3282,14 @@ namespace ICSharpCode.Decompiler.IL @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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;

14
ICSharpCode.Decompiler/IL/Instructions.tt

@ -146,24 +146,10 @@ @@ -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()")),

2
ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs

@ -61,8 +61,6 @@ namespace ICSharpCode.Decompiler.IL @@ -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:

35
ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs

@ -17,6 +17,7 @@ @@ -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 @@ -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;
}
/// <summary>
/// If this instruction is a conversion of the specified kind, return its argument.
/// Otherwise, return the instruction itself.

6
ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs

@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -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 @@ -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.

2
ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs

@ -170,7 +170,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -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<LdsFld>().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);

16
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -192,17 +192,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -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 @@ -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:

56
ICSharpCode.Decompiler/IL/Transforms/TransformInlineAssignment.cs

@ -36,20 +36,52 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -36,20 +36,52 @@ namespace ICSharpCode.Decompiler.IL.Transforms
this.context = context;
foreach (var block in function.Descendants.OfType<Block>()) {
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);
}
}
}
/// <code>
/// stloc s(value)
/// stloc l(ldloc s)
/// -->
/// stloc s(stloc l(value))
/// </code>
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));
}
/// <code>
/// stloc s(value)
/// stloc l(ldloc s)
/// stfld f(..., ldloc s)
/// -->
/// stloc l(stfld f(..., value))
/// </code>
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)));
}
}
}

17
ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.cs

@ -22,6 +22,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -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 @@ -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);
}
}
}

72
ICSharpCode.Decompiler/Tests/TestCases/Pretty/InlineAssignmentTest.il

@ -10,7 +10,7 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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
{

Loading…
Cancel
Save