diff --git a/ICSharpCode.Decompiler/IL/ILVariable.cs b/ICSharpCode.Decompiler/IL/ILVariable.cs
index eae0c89cb..66e47a773 100644
--- a/ICSharpCode.Decompiler/IL/ILVariable.cs
+++ b/ICSharpCode.Decompiler/IL/ILVariable.cs
@@ -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
/// It may change if an item with a lower index is removed from the collection.
///
public int IndexInFunction { get; internal set; }
-
+
///
/// Number of ldloc instructions referencing this variable.
///
///
/// This variable is automatically updated when adding/removing ldloc instructions from the ILAst.
///
- public int LoadCount { get; internal set; }
+ public int LoadCount => LoadInstructions.Count;
+
+ readonly List loadInstructions = new List();
+
+ ///
+ /// List of ldloc instructions referencing this variable.
+ ///
+ ///
+ /// This list is automatically updated when adding/removing ldloc instructions from the ILAst.
+ ///
+ public IReadOnlyList LoadInstructions => loadInstructions;
///
/// Number of store instructions referencing this variable.
@@ -138,15 +149,69 @@ namespace ICSharpCode.Decompiler.IL
///
/// This variable is automatically updated when adding/removing stores instructions from the ILAst.
///
- public int StoreCount { get; internal set; }
-
+ public int StoreCount => (hasInitialValue ? 1 : 0) + StoreInstructions.Count;
+
+ readonly List storeInstructions = new List();
+
+ ///
+ /// List of store instructions referencing this variable.
+ ///
+ /// Stores are:
+ ///
+ /// - stloc
+ /// - TryCatchHandler (assigning the exception variable)
+ /// - PinnedRegion (assigning the pointer variable)
+ /// - initial values ()
+ ///
+ ///
+ ///
+ /// This list is automatically updated when adding/removing stores instructions from the ILAst.
+ ///
+ public IReadOnlyList StoreInstructions => storeInstructions;
+
///
/// Number of ldloca instructions referencing this variable.
///
///
/// This variable is automatically updated when adding/removing ldloca instructions from the ILAst.
///
- public int AddressCount { get; internal set; }
+ public int AddressCount => AddressInstructions.Count;
+
+ readonly List addressInstructions = new List();
+
+ ///
+ /// List of ldloca instructions referencing this variable.
+ ///
+ ///
+ /// This list is automatically updated when adding/removing ldloca instructions from the ILAst.
+ ///
+ public IReadOnlyList 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(List list, T inst) where T : IInstructionWithVariableOperand
+ {
+ list.Add(inst);
+ return list.Count - 1;
+ }
+
+ void RemoveInstruction(List 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
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
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; }
}
}
diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs
index 020c1baa9..734f841a8 100644
--- a/ICSharpCode.Decompiler/IL/Instructions.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions.cs
@@ -677,7 +677,7 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL
{
/// A region where a pinned variable is used (initial representation of future fixed statement).
- 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
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
namespace ICSharpCode.Decompiler.IL
{
/// Catch handler within a try-catch statement.
- 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
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
namespace ICSharpCode.Decompiler.IL
{
/// Loads the value of a local variable. (ldarg/ldloc)
- 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
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
namespace ICSharpCode.Decompiler.IL
{
/// Loads the address of a local variable. (ldarga/ldloca)
- 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
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
namespace ICSharpCode.Decompiler.IL
{
/// Stores a value into a local variable. (starg/stloc)
- 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
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();
}
diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt
index 1a8756175..d51e325be 100644
--- a/ICSharpCode.Decompiler/IL/Instructions.tt
+++ b/ICSharpCode.Decompiler/IL/Instructions.tt
@@ -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));