Browse Source

Rename ILVariable.Scope to Function and introduce BlockContainer CaptureScope

pull/728/merge
Siegfried Pammer 9 years ago
parent
commit
0970b95d5f
  1. 16
      ICSharpCode.Decompiler/FlowAnalysis/DefiniteAssignmentVisitor.cs
  2. 30
      ICSharpCode.Decompiler/FlowAnalysis/ReachingDefinitionsVisitor.cs
  3. 4
      ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs
  4. 20
      ICSharpCode.Decompiler/IL/ILVariable.cs
  5. 10
      ICSharpCode.Decompiler/IL/Instructions.cs
  6. 4
      ICSharpCode.Decompiler/IL/Instructions.tt
  7. 21
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  8. 57
      ICSharpCode.Decompiler/IL/Instructions/ILVariableCollection.cs
  9. 2
      ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs
  10. 4
      ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs
  11. 4
      ICSharpCode.Decompiler/IL/Transforms/SplitVariables.cs

16
ICSharpCode.Decompiler/FlowAnalysis/DefiniteAssignmentVisitor.cs

@ -101,10 +101,10 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -101,10 +101,10 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
}
}
readonly ILVariableScope scope;
readonly ILFunction scope;
readonly BitSet variablesWithUninitializedUsage;
public DefiniteAssignmentVisitor(ILVariableScope scope)
public DefiniteAssignmentVisitor(ILFunction scope)
{
this.scope = scope;
this.variablesWithUninitializedUsage = new BitSet(scope.Variables.Count);
@ -114,15 +114,15 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -114,15 +114,15 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
public bool IsPotentiallyUsedUninitialized(ILVariable v)
{
Debug.Assert(v.Scope == scope);
return variablesWithUninitializedUsage[v.IndexInScope];
Debug.Assert(v.Function == scope);
return variablesWithUninitializedUsage[v.IndexInFunction];
}
void HandleStore(ILVariable v)
{
if (v.Scope == scope) {
if (v.Function == scope) {
// Mark the variable as initialized:
state.MarkVariableInitialized(v.IndexInScope);
state.MarkVariableInitialized(v.IndexInFunction);
// Note that this gets called even if the store is in unreachable code,
// but that's OK because bottomState.MarkVariableInitialized() has no effect.
@ -135,8 +135,8 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -135,8 +135,8 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
void EnsureInitialized(ILVariable v)
{
if (v.Scope == scope && state.IsPotentiallyUninitialized(v.IndexInScope)) {
variablesWithUninitializedUsage.Set(v.IndexInScope);
if (v.Function == scope && state.IsPotentiallyUninitialized(v.IndexInFunction)) {
variablesWithUninitializedUsage.Set(v.IndexInFunction);
}
}

30
ICSharpCode.Decompiler/FlowAnalysis/ReachingDefinitionsVisitor.cs

@ -193,7 +193,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -193,7 +193,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
/// <summary>
/// The function being analyzed.
/// </summary>
protected readonly ILVariableScope scope;
protected readonly ILFunction scope;
/// <summary>
/// All stores for all variables in the scope.
@ -234,12 +234,12 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -234,12 +234,12 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
/// The analysis will track all variables in the scope for which the predicate returns true
/// ("analyzed variables").
/// </summary>
public ReachingDefinitionsVisitor(ILVariableScope scope, Predicate<ILVariable> pred)
public ReachingDefinitionsVisitor(ILFunction scope, Predicate<ILVariable> pred)
: this(scope, GetActiveVariableBitSet(scope, pred))
{
}
static BitSet GetActiveVariableBitSet(ILVariableScope scope, Predicate<ILVariable> pred)
static BitSet GetActiveVariableBitSet(ILFunction scope, Predicate<ILVariable> pred)
{
if (scope == null)
throw new ArgumentNullException(nameof(scope));
@ -255,7 +255,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -255,7 +255,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
///
/// The analysis will track all variables in the scope for which <c>analyzedVariables[v.IndexInScope]</c> is true.
/// </summary>
public ReachingDefinitionsVisitor(ILVariableScope scope, BitSet analyzedVariables)
public ReachingDefinitionsVisitor(ILFunction scope, BitSet analyzedVariables)
{
if (scope == null)
throw new ArgumentNullException(nameof(scope));
@ -300,7 +300,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -300,7 +300,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
/// <summary>
/// Fill <c>allStores</c> and <c>storeIndexMap</c>.
/// </summary>
static List<ILInstruction>[] FindAllStoresByVariable(ILVariableScope scope, BitSet activeVariables)
static List<ILInstruction>[] FindAllStoresByVariable(ILFunction scope, BitSet activeVariables)
{
// For each variable, find the list of ILInstructions storing to that variable
List<ILInstruction>[] storesByVar = new List<ILInstruction>[scope.Variables.Count];
@ -311,8 +311,8 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -311,8 +311,8 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
foreach (var inst in scope.Descendants) {
if (inst.HasDirectFlag(InstructionFlags.MayWriteLocals)) {
ILVariable v = ((IInstructionWithVariableOperand)inst).Variable;
if (v.Scope == scope && activeVariables[v.IndexInScope]) {
storesByVar[v.IndexInScope].Add(inst);
if (v.Function == scope && activeVariables[v.IndexInFunction]) {
storesByVar[v.IndexInFunction].Add(inst);
}
}
}
@ -339,9 +339,9 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -339,9 +339,9 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
#region Analysis
void HandleStore(ILInstruction inst, ILVariable v)
{
if (v.Scope == scope && analyzedVariables[v.IndexInScope] && state.IsReachable) {
if (v.Function == scope && analyzedVariables[v.IndexInFunction] && state.IsReachable) {
// Clear the set of stores for this variable:
state.KillStores(firstStoreIndexForVariable[v.IndexInScope], firstStoreIndexForVariable[v.IndexInScope + 1]);
state.KillStores(firstStoreIndexForVariable[v.IndexInFunction], firstStoreIndexForVariable[v.IndexInFunction + 1]);
// And replace it with this store:
int si = storeIndexMap[inst];
state.SetStore(si);
@ -377,7 +377,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -377,7 +377,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
public bool IsAnalyzedVariable(ILVariable v)
{
return v.Scope == scope && analyzedVariables[v.IndexInScope];
return v.Function == scope && analyzedVariables[v.IndexInFunction];
}
/// <summary>
@ -387,9 +387,9 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -387,9 +387,9 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
/// </summary>
protected IEnumerable<ILInstruction> GetStores(State state, ILVariable v)
{
Debug.Assert(v.Scope == scope && analyzedVariables[v.IndexInScope]);
int endIndex = firstStoreIndexForVariable[v.IndexInScope + 1];
for (int si = firstStoreIndexForVariable[v.IndexInScope] + 1; si < endIndex; si++) {
Debug.Assert(v.Function == scope && analyzedVariables[v.IndexInFunction]);
int endIndex = firstStoreIndexForVariable[v.IndexInFunction + 1];
for (int si = firstStoreIndexForVariable[v.IndexInFunction] + 1; si < endIndex; si++) {
if (state.IsReachingStore(si)) {
Debug.Assert(((IInstructionWithVariableOperand)allStores[si]).Variable == v);
yield return allStores[si];
@ -404,8 +404,8 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -404,8 +404,8 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
/// </summary>
protected bool IsPotentiallyUninitialized(State state, ILVariable v)
{
Debug.Assert(v.Scope == scope && analyzedVariables[v.IndexInScope]);
return state.IsReachingStore(firstStoreIndexForVariable[v.IndexInScope]);
Debug.Assert(v.Function == scope && analyzedVariables[v.IndexInFunction]);
return state.IsReachingStore(firstStoreIndexForVariable[v.IndexInFunction]);
}
#endregion
}

4
ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs

@ -335,7 +335,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -335,7 +335,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
new PointerType(((ByReferenceType)oldVar.Type).ElementType),
oldVar.Index);
newVar.Name = oldVar.Name;
oldVar.Scope.Variables.Add(newVar);
oldVar.Function.Variables.Add(newVar);
ReplacePinnedVar(oldVar, newVar, pinnedRegion);
} else if (pinnedRegion.Variable.Type.IsKnownType(KnownTypeCode.String)) {
// fixing a string
@ -381,7 +381,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -381,7 +381,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (nativeVar.Kind == VariableKind.Local) {
newVar = new ILVariable(VariableKind.PinnedLocal, nativeVar.Type, nativeVar.Index);
newVar.Name = nativeVar.Name;
nativeVar.Scope.Variables.Add(newVar);
nativeVar.Function.Variables.Add(newVar);
ReplacePinnedVar(nativeVar, newVar, pinnedRegion);
} else {
newVar = nativeVar;

20
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -70,21 +70,31 @@ namespace ICSharpCode.Decompiler.IL @@ -70,21 +70,31 @@ namespace ICSharpCode.Decompiler.IL
public string Name { get; set; }
/// <summary>
/// Gets the scope in which this variable is declared.
/// Gets the function in which this variable is declared.
/// </summary>
/// <remarks>
/// This property is set automatically when the variable is added to the <c>VariableScope.Variables</c> collection.
/// This property is set automatically when the variable is added to the <c>ILFunction.Variables</c> collection.
/// </remarks>
public ILVariableScope Scope { get; internal set; }
public ILFunction Function { get; internal set; }
/// <summary>
/// Gets the index of this variable within the <c>VariableScope.Variables</c> collection.
/// Gets the block container in which this variable is captured.
/// For captured variables declared inside the loop, the capture scope is the BlockContainer of the loop.
/// For captured variables declared outside of the loop, the capture scope is the BlockContainer of the parent.
/// </summary>
/// <remarks>
/// This property returns null for variables that are not captured.
/// </remarks>
public BlockContainer CaptureScope { get; internal set; }
/// <summary>
/// Gets the index of this variable within the <c>Function.Variables</c> collection.
/// </summary>
/// <remarks>
/// This property is set automatically when the variable is added to the <c>VariableScope.Variables</c> collection.
/// It may change if an item with a lower index is removed from the collection.
/// </remarks>
public int IndexInScope { get; internal set; }
public int IndexInFunction { get; internal set; }
/// <summary>
/// Number of ldloc instructions referencing this variable.

10
ICSharpCode.Decompiler/IL/Instructions.cs

@ -513,7 +513,7 @@ namespace ICSharpCode.Decompiler.IL @@ -513,7 +513,7 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL
{
/// <summary>A container of IL blocks.</summary>
public sealed partial class ILFunction : ILVariableScope
public sealed partial class ILFunction : ILInstruction
{
public static readonly SlotInfo BodySlot = new SlotInfo("Body");
ILInstruction body;
@ -673,7 +673,7 @@ namespace ICSharpCode.Decompiler.IL @@ -673,7 +673,7 @@ namespace ICSharpCode.Decompiler.IL
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Scope));
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function));
}
public static readonly SlotInfo InitSlot = new SlotInfo("Init", canInlineInto: true);
ILInstruction init;
@ -1632,7 +1632,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1632,7 +1632,7 @@ namespace ICSharpCode.Decompiler.IL
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Scope));
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function));
}
public override StackType ResultType { get { return variable.StackType; } }
protected override InstructionFlags ComputeFlags()
@ -1707,7 +1707,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1707,7 +1707,7 @@ namespace ICSharpCode.Decompiler.IL
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Scope));
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function));
}
public override void WriteTo(ITextOutput output)
{
@ -1772,7 +1772,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1772,7 +1772,7 @@ namespace ICSharpCode.Decompiler.IL
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Scope));
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function));
}
public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true);
ILInstruction value;

4
ICSharpCode.Decompiler/IL/Instructions.tt

@ -45,7 +45,7 @@ @@ -45,7 +45,7 @@
CustomChildren(new [] {
new ChildInfo("body")
}), CustomConstructor, CustomWriteTo, CustomComputeFlags, CustomVariableName("function"), ResultType("O")
) { BaseClass = "ILVariableScope" },
),
new OpCode("BlockContainer", "A container of IL blocks.",
VoidResult, CustomConstructor, CustomVariableName("container"),
MatchCondition("Patterns.ListMatch.DoMatch(this.Blocks, o.Blocks, ref match)")),
@ -844,7 +844,7 @@ protected override void Disconnected() @@ -844,7 +844,7 @@ protected override void Disconnected()
opCode.Members.Add(@"internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Scope));
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Function));
}");
}
};

21
ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs

@ -25,19 +25,36 @@ using ICSharpCode.Decompiler.Disassembler; @@ -25,19 +25,36 @@ using ICSharpCode.Decompiler.Disassembler;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
using System.Diagnostics;
namespace ICSharpCode.Decompiler.IL
{
partial class ILFunction
{
public readonly MethodDefinition Method;
public readonly ILVariableCollection Variables;
public ILFunction(MethodDefinition method, ILInstruction body) : base(OpCode.ILFunction)
{
this.Body = body;
this.Method = method;
this.Variables = new ILVariableCollection(this);
}
internal override void CheckInvariant(ILPhase phase)
{
for (int i = 0; i < Variables.Count; i++) {
Debug.Assert(Variables[i].Function == this);
Debug.Assert(Variables[i].IndexInFunction == i);
}
base.CheckInvariant(phase);
}
protected void CloneVariables()
{
throw new NotImplementedException();
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);

57
ICSharpCode.Decompiler/IL/Instructions/VariableScope.cs → ICSharpCode.Decompiler/IL/Instructions/ILVariableCollection.cs

@ -23,47 +23,20 @@ using System.Diagnostics; @@ -23,47 +23,20 @@ using System.Diagnostics;
namespace ICSharpCode.Decompiler.IL
{
/// <summary>
/// An ILInstruction that provides a scope for local variables.
/// </summary>
public abstract class ILVariableScope : ILInstruction
{
public readonly ILVariableCollection Variables;
protected ILVariableScope(OpCode opCode) : base(opCode)
{
this.Variables = new ILVariableCollection(this);
}
internal override void CheckInvariant(ILPhase phase)
{
for (int i = 0; i < Variables.Count; i++) {
Debug.Assert(Variables[i].Scope == this);
Debug.Assert(Variables[i].IndexInScope == i);
}
base.CheckInvariant(phase);
}
protected void CloneVariables()
{
throw new NotImplementedException();
}
}
/// <summary>
/// The collection of variables in a <c>ILVariableScope</c>.
/// The collection of variables in a <c>ILFunction</c>.
/// </summary>
public class ILVariableCollection : ICollection<ILVariable>, IReadOnlyList<ILVariable>
{
readonly ILVariableScope scope;
readonly ILFunction scope;
readonly List<ILVariable> list = new List<ILVariable>();
internal ILVariableCollection(ILVariableScope scope)
internal ILVariableCollection(ILFunction scope)
{
this.scope = scope;
}
/// <summary>
/// Gets a variable given its <c>IndexInScope</c>.
/// Gets a variable given its <c>IndexInFunction</c>.
/// </summary>
public ILVariable this[int index] {
get {
@ -73,14 +46,14 @@ namespace ICSharpCode.Decompiler.IL @@ -73,14 +46,14 @@ namespace ICSharpCode.Decompiler.IL
public bool Add(ILVariable item)
{
if (item.Scope != null) {
if (item.Scope == scope)
if (item.Function != null) {
if (item.Function == scope)
return false;
else
throw new ArgumentException("Variable already belongs to another scope");
}
item.Scope = scope;
item.IndexInScope = list.Count;
item.Function = scope;
item.IndexInFunction = list.Count;
list.Add(item);
return true;
}
@ -93,23 +66,23 @@ namespace ICSharpCode.Decompiler.IL @@ -93,23 +66,23 @@ namespace ICSharpCode.Decompiler.IL
public void Clear()
{
foreach (var v in list) {
v.Scope = null;
v.Function = null;
}
list.Clear();
}
public bool Contains(ILVariable item)
{
Debug.Assert(item.Scope != scope || list[item.IndexInScope] == item);
return item.Scope == scope;
Debug.Assert(item.Function != scope || list[item.IndexInFunction] == item);
return item.Function == scope;
}
public bool Remove(ILVariable item)
{
if (item.Scope != scope)
if (item.Function != scope)
return false;
Debug.Assert(list[item.IndexInScope] == item);
RemoveAt(item.IndexInScope);
Debug.Assert(list[item.IndexInFunction] == item);
RemoveAt(item.IndexInFunction);
return true;
}
@ -117,7 +90,7 @@ namespace ICSharpCode.Decompiler.IL @@ -117,7 +90,7 @@ namespace ICSharpCode.Decompiler.IL
{
// swap-remove index
list[index] = list[list.Count - 1];
list[index].IndexInScope = index;
list[index].IndexInFunction = index;
list.RemoveAt(list.Count - 1);
}

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

@ -140,7 +140,7 @@ namespace ICSharpCode.Decompiler.IL @@ -140,7 +140,7 @@ namespace ICSharpCode.Decompiler.IL
base.CheckInvariant(phase);
Debug.Assert(Parent is TryCatch);
Debug.Assert(filter.ResultType == StackType.I4);
Debug.Assert(this.IsDescendantOf(variable.Scope));
Debug.Assert(this.IsDescendantOf(variable.Function));
}
public override StackType ResultType {

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

@ -49,9 +49,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -49,9 +49,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
};
block.Instructions.Insert(i++, new StLoc(uninlinedArgs[j], arg));
}
CollectionExtensions.AddRange(v.Scope.Variables, uninlinedArgs);
CollectionExtensions.AddRange(v.Function.Variables, uninlinedArgs);
// perform copy propagation:
foreach (var expr in v.Scope.Descendants) {
foreach (var expr in v.Function.Descendants) {
if (expr.MatchLdLoc(v)) {
var clone = copiedExpr.Clone();
for (int j = 0; j < uninlinedArgs.Length; j++) {

4
ICSharpCode.Decompiler/IL/Transforms/SplitVariables.cs

@ -67,7 +67,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -67,7 +67,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
readonly UnionFind<IInstructionWithVariableOperand> unionFind = new UnionFind<IInstructionWithVariableOperand>();
readonly HashSet<IInstructionWithVariableOperand> uninitVariableUsage = new HashSet<IInstructionWithVariableOperand>();
public GroupStores(ILVariableScope scope) : base(scope, IsCandidateVariable)
public GroupStores(ILFunction scope) : base(scope, IsCandidateVariable)
{
}
@ -98,7 +98,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -98,7 +98,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
v.Name = inst.Variable.Name;
v.HasInitialValue = false; // we'll set HasInitialValue when we encounter an uninit load
newVariables.Add(representative, v);
inst.Variable.Scope.Variables.Add(v);
inst.Variable.Function.Variables.Add(v);
}
if (uninitVariableUsage.Contains(inst)) {
v.HasInitialValue = true;

Loading…
Cancel
Save