Browse Source

Redesign of UsingInstruction.

pull/877/head
Siegfried Pammer 8 years ago
parent
commit
d1a514b451
  1. 54
      ICSharpCode.Decompiler/IL/Instructions.cs
  2. 2
      ICSharpCode.Decompiler/IL/Instructions.tt
  3. 14
      ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs
  4. 16
      ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

54
ICSharpCode.Decompiler/IL/Instructions.cs

@ -1701,13 +1701,53 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
/// <summary>Using statement</summary> /// <summary>Using statement</summary>
public sealed partial class UsingInstruction : ILInstruction public sealed partial class UsingInstruction : ILInstruction, IStoreInstruction
{ {
public UsingInstruction(ILInstruction resourceExpression, ILInstruction body) : base(OpCode.UsingInstruction) public UsingInstruction(ILVariable variable, ILInstruction resourceExpression, ILInstruction body) : base(OpCode.UsingInstruction)
{ {
Debug.Assert(variable != null);
this.variable = variable;
this.ResourceExpression = resourceExpression; this.ResourceExpression = resourceExpression;
this.Body = body; this.Body = body;
} }
ILVariable variable;
public ILVariable Variable {
get { return variable; }
set {
Debug.Assert(value != null);
if (IsConnected)
variable.RemoveStoreInstruction(this);
variable = value;
if (IsConnected)
variable.AddStoreInstruction(this);
}
}
public int IndexInStoreInstructionList { get; set; } = -1;
int IInstructionWithVariableOperand.IndexInVariableInstructionMapping {
get { return ((IStoreInstruction)this).IndexInStoreInstructionList; }
set { ((IStoreInstruction)this).IndexInStoreInstructionList = value; }
}
protected override void Connected()
{
base.Connected();
variable.AddStoreInstruction(this);
}
protected override void Disconnected()
{
variable.RemoveStoreInstruction(this);
base.Disconnected();
}
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function));
Debug.Assert(phase <= ILPhase.InILReader || variable.Function.Variables[variable.IndexInFunction] == variable);
}
public static readonly SlotInfo ResourceExpressionSlot = new SlotInfo("ResourceExpression", canInlineInto: true); public static readonly SlotInfo ResourceExpressionSlot = new SlotInfo("ResourceExpression", canInlineInto: true);
ILInstruction resourceExpression; ILInstruction resourceExpression;
public ILInstruction ResourceExpression { public ILInstruction ResourceExpression {
@ -1775,11 +1815,11 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.Void; } } public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return resourceExpression.Flags | body.Flags | InstructionFlags.ControlFlow | InstructionFlags.SideEffect; return InstructionFlags.MayWriteLocals | resourceExpression.Flags | body.Flags | InstructionFlags.ControlFlow | InstructionFlags.SideEffect;
} }
public override InstructionFlags DirectFlags { public override InstructionFlags DirectFlags {
get { get {
return InstructionFlags.ControlFlow | InstructionFlags.SideEffect; return InstructionFlags.MayWriteLocals | InstructionFlags.ControlFlow | InstructionFlags.SideEffect;
} }
} }
public override void AcceptVisitor(ILVisitor visitor) public override void AcceptVisitor(ILVisitor visitor)
@ -1797,7 +1837,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match) protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{ {
var o = other as UsingInstruction; var o = other as UsingInstruction;
return o != null && this.resourceExpression.PerformMatch(o.resourceExpression, ref match) && this.body.PerformMatch(o.body, ref match); return o != null && variable == o.variable && this.resourceExpression.PerformMatch(o.resourceExpression, ref match) && this.body.PerformMatch(o.body, ref match);
} }
} }
} }
@ -5337,14 +5377,16 @@ namespace ICSharpCode.Decompiler.IL
body = default(ILInstruction); body = default(ILInstruction);
return false; return false;
} }
public bool MatchUsingInstruction(out ILInstruction resourceExpression, out ILInstruction body) public bool MatchUsingInstruction(out ILVariable variable, out ILInstruction resourceExpression, out ILInstruction body)
{ {
var inst = this as UsingInstruction; var inst = this as UsingInstruction;
if (inst != null) { if (inst != null) {
variable = inst.Variable;
resourceExpression = inst.ResourceExpression; resourceExpression = inst.ResourceExpression;
body = inst.Body; body = inst.Body;
return true; return true;
} }
variable = default(ILVariable);
resourceExpression = default(ILInstruction); resourceExpression = default(ILInstruction);
body = default(ILInstruction); body = default(ILInstruction);
return false; return false;

2
ICSharpCode.Decompiler/IL/Instructions.tt

@ -119,7 +119,7 @@
new ArgumentInfo("onExpression"), new ArgumentInfo("onExpression"),
new ChildInfo("body") new ChildInfo("body")
}), CustomWriteTo, ControlFlow, SideEffect, ResultType("Void")), }), CustomWriteTo, ControlFlow, SideEffect, ResultType("Void")),
new OpCode("using", "Using statement", CustomClassName("UsingInstruction"), new OpCode("using", "Using statement", CustomClassName("UsingInstruction"), HasVariableOperand("Store"),
CustomChildren(new [] { CustomChildren(new [] {
new ArgumentInfo("resourceExpression"), new ArgumentInfo("resourceExpression"),
new ChildInfo("body") new ChildInfo("body")

14
ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs

@ -39,11 +39,25 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
/// <summary>
/// IL using instruction.
/// Equivalent to:
/// <code>
/// stloc v(resourceExpression)
/// try {
/// body
/// } finally {
/// v?.Dispose();
/// }
/// </code>
/// </summary>
partial class UsingInstruction partial class UsingInstruction
{ {
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
output.Write("using ("); output.Write("using (");
Variable.WriteTo(output);
output.Write(" = ");
ResourceExpression.WriteTo(output, options); ResourceExpression.WriteTo(output, options);
output.WriteLine(") {"); output.WriteLine(") {");
output.Indent(); output.Indent();

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

@ -76,23 +76,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!(body.FinallyBlock is BlockContainer container) || !MatchDisposeBlock(container, storeInst.Variable, storeInst.Value.MatchLdNull())) if (!(body.FinallyBlock is BlockContainer container) || !MatchDisposeBlock(container, storeInst.Variable, storeInst.Value.MatchLdNull()))
return false; return false;
ILInstruction resourceExpression;
if (storeInst.Variable.Type.IsReferenceType != false) {
if (storeInst.Variable.IsSingleDefinition && storeInst.Variable.LoadCount <= 2) {
resourceExpression = storeInst.Value;
} else {
resourceExpression = storeInst;
}
} else {
if (storeInst.Variable.StoreCount == 1 && storeInst.Variable.LoadCount == 0 && storeInst.Variable.AddressCount == 1) {
resourceExpression = storeInst.Value;
} else {
resourceExpression = storeInst;
}
}
context.Step("UsingTransform", body); context.Step("UsingTransform", body);
block.Instructions.RemoveAt(i); block.Instructions.RemoveAt(i);
block.Instructions[i - 1] = new UsingInstruction(resourceExpression, body.TryBlock); block.Instructions[i - 1] = new UsingInstruction(storeInst.Variable, storeInst.Value, body.TryBlock);
return true; return true;
} }

Loading…
Cancel
Save