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 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL
@ -115,14 +116,24 @@ 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.
/// </remarks>
public int IndexInFunction { get; internal set; }
/// <summary>
/// Number of ldloc instructions referencing this variable.
/// </summary>
/// <remarks>
/// This variable is automatically updated when adding/removing ldloc instructions from the ILAst.
/// </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>
/// Number of store instructions referencing this variable.
@ -138,15 +149,69 @@ namespace ICSharpCode.Decompiler.IL @@ -138,15 +149,69 @@ namespace ICSharpCode.Decompiler.IL
/// <remarks>
/// This variable is automatically updated when adding/removing stores instructions from the ILAst.
/// </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>
/// Number of ldloca instructions referencing this variable.
/// </summary>
/// <remarks>
/// This variable is automatically updated when adding/removing ldloca instructions from the ILAst.
/// </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;
@ -165,13 +230,7 @@ namespace ICSharpCode.Decompiler.IL @@ -165,13 +230,7 @@ namespace ICSharpCode.Decompiler.IL
set {
if (Kind == VariableKind.Parameter && !value)
throw new InvalidOperationException("Cannot remove HasInitialValue from parameters");
if (hasInitialValue) {
StoreCount--;
}
hasInitialValue = value;
if (value) {
StoreCount++;
}
}
}
@ -254,5 +313,21 @@ namespace ICSharpCode.Decompiler.IL @@ -254,5 +313,21 @@ namespace ICSharpCode.Decompiler.IL
public interface IInstructionWithVariableOperand
{
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 @@ -677,7 +677,7 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL
{
/// <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)
{
@ -693,21 +693,29 @@ namespace ICSharpCode.Decompiler.IL @@ -693,21 +693,29 @@ namespace ICSharpCode.Decompiler.IL
set {
Debug.Assert(value != null);
if (IsConnected)
variable.StoreCount--;
variable.RemoveStoreInstruction(this);
variable = value;
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()
{
base.Connected();
variable.StoreCount++;
variable.AddStoreInstruction(this);
}
protected override void Disconnected()
{
variable.StoreCount--;
variable.RemoveStoreInstruction(this);
base.Disconnected();
}
@ -1300,7 +1308,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1300,7 +1308,7 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL
{
/// <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)
{
@ -1379,21 +1387,29 @@ namespace ICSharpCode.Decompiler.IL @@ -1379,21 +1387,29 @@ namespace ICSharpCode.Decompiler.IL
set {
Debug.Assert(value != null);
if (IsConnected)
variable.StoreCount--;
variable.RemoveStoreInstruction(this);
variable = value;
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()
{
base.Connected();
variable.StoreCount++;
variable.AddStoreInstruction(this);
}
protected override void Disconnected()
{
variable.StoreCount--;
variable.RemoveStoreInstruction(this);
base.Disconnected();
}
@ -1639,7 +1655,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1639,7 +1655,7 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL
{
/// <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)
{
@ -1652,21 +1668,29 @@ namespace ICSharpCode.Decompiler.IL @@ -1652,21 +1668,29 @@ namespace ICSharpCode.Decompiler.IL
set {
Debug.Assert(value != null);
if (IsConnected)
variable.LoadCount--;
variable.RemoveLoadInstruction(this);
variable = value;
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()
{
base.Connected();
variable.LoadCount++;
variable.AddLoadInstruction(this);
}
protected override void Disconnected()
{
variable.LoadCount--;
variable.RemoveLoadInstruction(this);
base.Disconnected();
}
@ -1713,7 +1737,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1713,7 +1737,7 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL
{
/// <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)
{
@ -1727,21 +1751,29 @@ namespace ICSharpCode.Decompiler.IL @@ -1727,21 +1751,29 @@ namespace ICSharpCode.Decompiler.IL
set {
Debug.Assert(value != null);
if (IsConnected)
variable.AddressCount--;
variable.RemoveAddressInstruction(this);
variable = value;
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()
{
base.Connected();
variable.AddressCount++;
variable.AddAddressInstruction(this);
}
protected override void Disconnected()
{
variable.AddressCount--;
variable.RemoveAddressInstruction(this);
base.Disconnected();
}
@ -1778,7 +1810,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1778,7 +1810,7 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL
{
/// <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)
{
@ -1792,21 +1824,29 @@ namespace ICSharpCode.Decompiler.IL @@ -1792,21 +1824,29 @@ namespace ICSharpCode.Decompiler.IL
set {
Debug.Assert(value != null);
if (IsConnected)
variable.StoreCount--;
variable.RemoveStoreInstruction(this);
variable = value;
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()
{
base.Connected();
variable.StoreCount++;
variable.AddStoreInstruction(this);
}
protected override void Disconnected()
{
variable.StoreCount--;
variable.RemoveStoreInstruction(this);
base.Disconnected();
}

18
ICSharpCode.Decompiler/IL/Instructions.tt

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

Loading…
Cancel
Save