Browse Source

Add instruction<->variable mapping to ILVariable

pull/728/merge
Siegfried Pammer 9 years ago
parent
commit
54a48b520e
  1. 97
      ICSharpCode.Decompiler/IL/ILVariable.cs
  2. 90
      ICSharpCode.Decompiler/IL/Instructions.cs
  3. 18
      ICSharpCode.Decompiler/IL/Instructions.tt

97
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
@ -115,14 +116,24 @@ namespace ICSharpCode.Decompiler.IL
/// It may change if an item with a lower index is removed from the collection. /// It may change if an item with a lower index is removed from the collection.
/// </remarks> /// </remarks>
public int IndexInFunction { get; internal set; } public int IndexInFunction { get; internal set; }
/// <summary> /// <summary>
/// Number of ldloc instructions referencing this variable. /// Number of ldloc instructions referencing this variable.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This variable is automatically updated when adding/removing ldloc instructions from the ILAst. /// This variable is automatically updated when adding/removing ldloc instructions from the ILAst.
/// </remarks> /// </remarks>
public int LoadCount { get; internal set; } public int LoadCount => LoadInstructions.Count;
readonly List<ILoadInstruction> loadInstructions = new List<ILoadInstruction>();
/// <summary>
/// List of ldloc instructions referencing this variable.
/// </summary>
/// <remarks>
/// This list is automatically updated when adding/removing ldloc instructions from the ILAst.
/// </remarks>
public IReadOnlyList<ILoadInstruction> LoadInstructions => loadInstructions;
/// <summary> /// <summary>
/// Number of store instructions referencing this variable. /// Number of store instructions referencing this variable.
@ -138,15 +149,69 @@ namespace ICSharpCode.Decompiler.IL
/// <remarks> /// <remarks>
/// This variable is automatically updated when adding/removing stores instructions from the ILAst. /// This variable is automatically updated when adding/removing stores instructions from the ILAst.
/// </remarks> /// </remarks>
public int StoreCount { get; internal set; } public int StoreCount => (hasInitialValue ? 1 : 0) + StoreInstructions.Count;
readonly List<IStoreInstruction> storeInstructions = new List<IStoreInstruction>();
/// <summary>
/// List of store instructions referencing this variable.
///
/// Stores are:
/// <list type="item">
/// <item>stloc</item>
/// <item>TryCatchHandler (assigning the exception variable)</item>
/// <item>PinnedRegion (assigning the pointer variable)</item>
/// <item>initial values (<see cref="HasInitialValue"/>)</item>
/// </list>
/// </summary>
/// <remarks>
/// This list is automatically updated when adding/removing stores instructions from the ILAst.
/// </remarks>
public IReadOnlyList<IStoreInstruction> StoreInstructions => storeInstructions;
/// <summary> /// <summary>
/// Number of ldloca instructions referencing this variable. /// Number of ldloca instructions referencing this variable.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This variable is automatically updated when adding/removing ldloca instructions from the ILAst. /// This variable is automatically updated when adding/removing ldloca instructions from the ILAst.
/// </remarks> /// </remarks>
public int AddressCount { get; internal set; } public int AddressCount => AddressInstructions.Count;
readonly List<LdLoca> addressInstructions = new List<LdLoca>();
/// <summary>
/// List of ldloca instructions referencing this variable.
/// </summary>
/// <remarks>
/// This list is automatically updated when adding/removing ldloca instructions from the ILAst.
/// </remarks>
public IReadOnlyList<LdLoca> AddressInstructions => addressInstructions;
internal void AddLoadInstruction(ILoadInstruction inst) => inst.IndexInLoadInstructionList = AddInstruction(loadInstructions, inst);
internal void AddStoreInstruction(IStoreInstruction inst) => inst.IndexInStoreInstructionList = AddInstruction(storeInstructions, inst);
internal void AddAddressInstruction(LdLoca inst) => inst.IndexInAddressInstructionList = AddInstruction(addressInstructions, inst);
internal void RemoveLoadInstruction(ILoadInstruction inst) => RemoveInstruction(loadInstructions, inst.IndexInLoadInstructionList);
internal void RemoveStoreInstruction(IStoreInstruction inst) => RemoveInstruction(storeInstructions, inst.IndexInStoreInstructionList);
internal void RemoveAddressInstruction(LdLoca inst) => RemoveInstruction(addressInstructions, inst.IndexInAddressInstructionList);
int AddInstruction<T>(List<T> list, T inst) where T : IInstructionWithVariableOperand
{
list.Add(inst);
return list.Count - 1;
}
void RemoveInstruction<T>(List<T> list, int index) where T : IInstructionWithVariableOperand
{
if (list.Count > 1) {
int indexToMove = list.Count - 1;
list[index] = list[indexToMove];
list[index].IndexInVariableInstructionMapping = index;
list.RemoveAt(indexToMove);
} else {
list.RemoveAt(0);
}
}
bool hasInitialValue; bool hasInitialValue;
@ -165,13 +230,7 @@ namespace ICSharpCode.Decompiler.IL
set { set {
if (Kind == VariableKind.Parameter && !value) if (Kind == VariableKind.Parameter && !value)
throw new InvalidOperationException("Cannot remove HasInitialValue from parameters"); throw new InvalidOperationException("Cannot remove HasInitialValue from parameters");
if (hasInitialValue) {
StoreCount--;
}
hasInitialValue = value; hasInitialValue = value;
if (value) {
StoreCount++;
}
} }
} }
@ -254,5 +313,21 @@ namespace ICSharpCode.Decompiler.IL
public interface IInstructionWithVariableOperand public interface IInstructionWithVariableOperand
{ {
ILVariable Variable { get; set; } ILVariable Variable { get; set; }
int IndexInVariableInstructionMapping { get; set; }
}
public interface IStoreInstruction : IInstructionWithVariableOperand
{
int IndexInStoreInstructionList { get; set; }
}
public interface ILoadInstruction : IInstructionWithVariableOperand
{
int IndexInLoadInstructionList { get; set; }
}
public interface IAddressInstruction : IInstructionWithVariableOperand
{
int IndexInAddressInstructionList { get; set; }
} }
} }

90
ICSharpCode.Decompiler/IL/Instructions.cs

@ -677,7 +677,7 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
/// <summary>A region where a pinned variable is used (initial representation of future fixed statement).</summary> /// <summary>A region where a pinned variable is used (initial representation of future fixed statement).</summary>
public sealed partial class PinnedRegion : ILInstruction, IInstructionWithVariableOperand public sealed partial class PinnedRegion : ILInstruction, IStoreInstruction
{ {
public PinnedRegion(ILVariable variable, ILInstruction init, ILInstruction body) : base(OpCode.PinnedRegion) public PinnedRegion(ILVariable variable, ILInstruction init, ILInstruction body) : base(OpCode.PinnedRegion)
{ {
@ -693,21 +693,29 @@ namespace ICSharpCode.Decompiler.IL
set { set {
Debug.Assert(value != null); Debug.Assert(value != null);
if (IsConnected) if (IsConnected)
variable.StoreCount--; variable.RemoveStoreInstruction(this);
variable = value; variable = value;
if (IsConnected) if (IsConnected)
variable.StoreCount++; 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() protected override void Connected()
{ {
base.Connected(); base.Connected();
variable.StoreCount++; variable.AddStoreInstruction(this);
} }
protected override void Disconnected() protected override void Disconnected()
{ {
variable.StoreCount--; variable.RemoveStoreInstruction(this);
base.Disconnected(); base.Disconnected();
} }
@ -1300,7 +1308,7 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
/// <summary>Catch handler within a try-catch statement.</summary> /// <summary>Catch handler within a try-catch statement.</summary>
public sealed partial class TryCatchHandler : ILInstruction, IInstructionWithVariableOperand public sealed partial class TryCatchHandler : ILInstruction, IStoreInstruction
{ {
public TryCatchHandler(ILInstruction filter, ILInstruction body, ILVariable variable) : base(OpCode.TryCatchHandler) public TryCatchHandler(ILInstruction filter, ILInstruction body, ILVariable variable) : base(OpCode.TryCatchHandler)
{ {
@ -1379,21 +1387,29 @@ namespace ICSharpCode.Decompiler.IL
set { set {
Debug.Assert(value != null); Debug.Assert(value != null);
if (IsConnected) if (IsConnected)
variable.StoreCount--; variable.RemoveStoreInstruction(this);
variable = value; variable = value;
if (IsConnected) if (IsConnected)
variable.StoreCount++; 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() protected override void Connected()
{ {
base.Connected(); base.Connected();
variable.StoreCount++; variable.AddStoreInstruction(this);
} }
protected override void Disconnected() protected override void Disconnected()
{ {
variable.StoreCount--; variable.RemoveStoreInstruction(this);
base.Disconnected(); base.Disconnected();
} }
@ -1639,7 +1655,7 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
/// <summary>Loads the value of a local variable. (ldarg/ldloc)</summary> /// <summary>Loads the value of a local variable. (ldarg/ldloc)</summary>
public sealed partial class LdLoc : SimpleInstruction, IInstructionWithVariableOperand public sealed partial class LdLoc : SimpleInstruction, ILoadInstruction
{ {
public LdLoc(ILVariable variable) : base(OpCode.LdLoc) public LdLoc(ILVariable variable) : base(OpCode.LdLoc)
{ {
@ -1652,21 +1668,29 @@ namespace ICSharpCode.Decompiler.IL
set { set {
Debug.Assert(value != null); Debug.Assert(value != null);
if (IsConnected) if (IsConnected)
variable.LoadCount--; variable.RemoveLoadInstruction(this);
variable = value; variable = value;
if (IsConnected) if (IsConnected)
variable.LoadCount++; variable.AddLoadInstruction(this);
} }
} }
public int IndexInLoadInstructionList { get; set; } = -1;
int IInstructionWithVariableOperand.IndexInVariableInstructionMapping {
get { return ((ILoadInstruction)this).IndexInLoadInstructionList; }
set { ((ILoadInstruction)this).IndexInLoadInstructionList = value; }
}
protected override void Connected() protected override void Connected()
{ {
base.Connected(); base.Connected();
variable.LoadCount++; variable.AddLoadInstruction(this);
} }
protected override void Disconnected() protected override void Disconnected()
{ {
variable.LoadCount--; variable.RemoveLoadInstruction(this);
base.Disconnected(); base.Disconnected();
} }
@ -1713,7 +1737,7 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
/// <summary>Loads the address of a local variable. (ldarga/ldloca)</summary> /// <summary>Loads the address of a local variable. (ldarga/ldloca)</summary>
public sealed partial class LdLoca : SimpleInstruction, IInstructionWithVariableOperand public sealed partial class LdLoca : SimpleInstruction, IAddressInstruction
{ {
public LdLoca(ILVariable variable) : base(OpCode.LdLoca) public LdLoca(ILVariable variable) : base(OpCode.LdLoca)
{ {
@ -1727,21 +1751,29 @@ namespace ICSharpCode.Decompiler.IL
set { set {
Debug.Assert(value != null); Debug.Assert(value != null);
if (IsConnected) if (IsConnected)
variable.AddressCount--; variable.RemoveAddressInstruction(this);
variable = value; variable = value;
if (IsConnected) if (IsConnected)
variable.AddressCount++; variable.AddAddressInstruction(this);
} }
} }
public int IndexInAddressInstructionList { get; set; } = -1;
int IInstructionWithVariableOperand.IndexInVariableInstructionMapping {
get { return ((IAddressInstruction)this).IndexInAddressInstructionList; }
set { ((IAddressInstruction)this).IndexInAddressInstructionList = value; }
}
protected override void Connected() protected override void Connected()
{ {
base.Connected(); base.Connected();
variable.AddressCount++; variable.AddAddressInstruction(this);
} }
protected override void Disconnected() protected override void Disconnected()
{ {
variable.AddressCount--; variable.RemoveAddressInstruction(this);
base.Disconnected(); base.Disconnected();
} }
@ -1778,7 +1810,7 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
/// <summary>Stores a value into a local variable. (starg/stloc)</summary> /// <summary>Stores a value into a local variable. (starg/stloc)</summary>
public sealed partial class StLoc : ILInstruction, IInstructionWithVariableOperand public sealed partial class StLoc : ILInstruction, IStoreInstruction
{ {
public StLoc(ILVariable variable, ILInstruction value) : base(OpCode.StLoc) public StLoc(ILVariable variable, ILInstruction value) : base(OpCode.StLoc)
{ {
@ -1792,21 +1824,29 @@ namespace ICSharpCode.Decompiler.IL
set { set {
Debug.Assert(value != null); Debug.Assert(value != null);
if (IsConnected) if (IsConnected)
variable.StoreCount--; variable.RemoveStoreInstruction(this);
variable = value; variable = value;
if (IsConnected) if (IsConnected)
variable.StoreCount++; 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() protected override void Connected()
{ {
base.Connected(); base.Connected();
variable.StoreCount++; variable.AddStoreInstruction(this);
} }
protected override void Disconnected() protected override void Disconnected()
{ {
variable.StoreCount--; variable.RemoveStoreInstruction(this);
base.Disconnected(); base.Disconnected();
} }

18
ICSharpCode.Decompiler/IL/Instructions.tt

@ -824,27 +824,35 @@ namespace ICSharpCode.Decompiler.IL
opCode.GenerateWriteTo = true; opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("output.Write(' ');"); opCode.WriteOperand.Add("output.Write(' ');");
opCode.WriteOperand.Add("variable.WriteTo(output);"); opCode.WriteOperand.Add("variable.WriteTo(output);");
opCode.Interfaces.Add("IInstructionWithVariableOperand"); opCode.Interfaces.Add("I" + accessType + "Instruction");
opCode.Members.Add(@"public ILVariable Variable { opCode.Members.Add(@"public ILVariable Variable {
get { return variable; } get { return variable; }
set { set {
Debug.Assert(value != null); Debug.Assert(value != null);
if (IsConnected) if (IsConnected)
variable.AccessCount--; variable.RemoveAccessInstruction(this);
variable = value; variable = value;
if (IsConnected) if (IsConnected)
variable.AccessCount++; variable.AddAccessInstruction(this);
} }
} }
public int IndexInAccessInstructionList { get; set; } = -1;
int IInstructionWithVariableOperand.IndexInVariableInstructionMapping {
get { return ((IAccessInstruction)this).IndexInAccessInstructionList; }
set { ((IAccessInstruction)this).IndexInAccessInstructionList = value; }
}
protected override void Connected() protected override void Connected()
{ {
base.Connected(); base.Connected();
variable.AccessCount++; variable.AddAccessInstruction(this);
} }
protected override void Disconnected() protected override void Disconnected()
{ {
variable.AccessCount--; variable.RemoveAccessInstruction(this);
base.Disconnected(); base.Disconnected();
} }
".Replace("Access", accessType)); ".Replace("Access", accessType));

Loading…
Cancel
Save