Browse Source

Add class VariableScope.

pull/728/head
Daniel Grunwald 9 years ago
parent
commit
c171dbd520
  1. 4
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 5
      ICSharpCode.Decompiler/FlowAnalysis/ReachingDefinitions.cs
  3. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  4. 14
      ICSharpCode.Decompiler/IL/ILReader.cs
  5. 17
      ICSharpCode.Decompiler/IL/ILVariable.cs
  6. 2
      ICSharpCode.Decompiler/IL/Instructions.cs
  7. 3
      ICSharpCode.Decompiler/IL/Instructions.tt
  8. 4
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  9. 4
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  10. 4
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  11. 10
      ICSharpCode.Decompiler/IL/Instructions/Branch.cs
  12. 1
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  13. 18
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  14. 4
      ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
  15. 6
      ICSharpCode.Decompiler/IL/Instructions/Leave.cs
  16. 19
      ICSharpCode.Decompiler/IL/Instructions/LocalVarInstructions.cs
  17. 13
      ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs
  18. 162
      ICSharpCode.Decompiler/IL/Instructions/VariableScope.cs
  19. 3
      ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs

4
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -557,12 +557,12 @@ namespace ICSharpCode.Decompiler.CSharp
var specializingTypeSystem = GetSpecializingTypeSystem(decompilationContext); var specializingTypeSystem = GetSpecializingTypeSystem(decompilationContext);
var ilReader = new ILReader(specializingTypeSystem); var ilReader = new ILReader(specializingTypeSystem);
var function = ilReader.ReadIL(methodDefinition.Body, CancellationToken); var function = ilReader.ReadIL(methodDefinition.Body, CancellationToken);
function.CheckInvariant(); function.CheckInvariant(ILPhase.Normal);
var context = new ILTransformContext { TypeSystem = specializingTypeSystem, CancellationToken = CancellationToken }; var context = new ILTransformContext { TypeSystem = specializingTypeSystem, CancellationToken = CancellationToken };
foreach (var transform in ilTransforms) { foreach (var transform in ilTransforms) {
CancellationToken.ThrowIfCancellationRequested(); CancellationToken.ThrowIfCancellationRequested();
transform.Run(function, context); transform.Run(function, context);
function.CheckInvariant(); function.CheckInvariant(ILPhase.Normal);
} }
var statementBuilder = new StatementBuilder(decompilationContext, method); var statementBuilder = new StatementBuilder(decompilationContext, method);
var body = statementBuilder.ConvertAsBlock(function.Body); var body = statementBuilder.ConvertAsBlock(function.Body);

5
ICSharpCode.Decompiler/FlowAnalysis/ReachingDefinitions.cs

@ -21,14 +21,11 @@ using System;
namespace ICSharpCode.Decompiler.FlowAnalysis namespace ICSharpCode.Decompiler.FlowAnalysis
{ {
/// <summary> /// <summary>
/// Implements the "reaching defintions" analysis. /// Implements the "reaching definitions" analysis.
/// ///
/// https://en.wikipedia.org/wiki/Reaching_definition /// https://en.wikipedia.org/wiki/Reaching_definition
/// </summary> /// </summary>
public class ReachingDefinitions public class ReachingDefinitions
{ {
public ReachingDefinitions()
{
}
} }
} }

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -115,6 +115,7 @@
<Compile Include="IL\Instructions\TryInstruction.cs" /> <Compile Include="IL\Instructions\TryInstruction.cs" />
<Compile Include="IL\Instructions\UnaryInstruction.cs" /> <Compile Include="IL\Instructions\UnaryInstruction.cs" />
<Compile Include="IL\IInlineContext.cs" /> <Compile Include="IL\IInlineContext.cs" />
<Compile Include="IL\Instructions\VariableScope.cs" />
<Compile Include="IL\NRTypeExtensions.cs" /> <Compile Include="IL\NRTypeExtensions.cs" />
<Compile Include="IL\SlotInfo.cs" /> <Compile Include="IL\SlotInfo.cs" />
<Compile Include="IL\Transforms\CopyPropagation.cs" /> <Compile Include="IL\Transforms\CopyPropagation.cs" />

14
ICSharpCode.Decompiler/IL/ILReader.cs

@ -235,7 +235,7 @@ namespace ICSharpCode.Decompiler.IL
ILInstruction decodedInstruction = DecodeInstruction(); ILInstruction decodedInstruction = DecodeInstruction();
if (decodedInstruction.ResultType == StackType.Unknown) if (decodedInstruction.ResultType == StackType.Unknown)
Warn("Unknown result type (might be due to invalid IL)"); Warn("Unknown result type (might be due to invalid IL)");
decodedInstruction.CheckInvariant(); decodedInstruction.CheckInvariant(ILPhase.InILReader);
decodedInstruction.ILRange = new Interval(start, reader.Position); decodedInstruction.ILRange = new Interval(start, reader.Position);
UnpackPush(decodedInstruction).ILRange = decodedInstruction.ILRange; UnpackPush(decodedInstruction).ILRange = decodedInstruction.ILRange;
instructionBuilder.Add(decodedInstruction); instructionBuilder.Add(decodedInstruction);
@ -298,6 +298,7 @@ namespace ICSharpCode.Decompiler.IL
function.Variables.AddRange(parameterVariables); function.Variables.AddRange(parameterVariables);
function.Variables.AddRange(localVariables); function.Variables.AddRange(localVariables);
function.Variables.AddRange(stackVariables); function.Variables.AddRange(stackVariables);
function.Variables.AddRange(variableByExceptionHandler.Values);
function.AddRef(); // mark the root node function.AddRef(); // mark the root node
return function; return function;
} }
@ -968,21 +969,22 @@ namespace ICSharpCode.Decompiler.IL
} }
switch (method.DeclaringType.Kind) { switch (method.DeclaringType.Kind) {
case TypeKind.Array: case TypeKind.Array:
var type = ((ICSharpCode.NRefactory.TypeSystem.ArrayType)method.DeclaringType).ElementType; var elementType = ((ICSharpCode.NRefactory.TypeSystem.ArrayType)method.DeclaringType).ElementType;
if (opCode == OpCode.NewObj) if (opCode == OpCode.NewObj)
return Push(new NewArr(type, arguments)); return Push(new NewArr(elementType, arguments));
if (method.Name == "Set") { if (method.Name == "Set") {
var target = arguments[0]; var target = arguments[0];
var value = arguments.Last(); var value = arguments.Last();
var indices = arguments.Skip(1).Take(arguments.Length - 2).ToArray(); var indices = arguments.Skip(1).Take(arguments.Length - 2).ToArray();
return new StObj(new LdElema(type, target, indices), value, type); return new StObj(new LdElema(elementType, target, indices), value, elementType);
} }
if (method.Name == "Get") { if (method.Name == "Get") {
var target = arguments[0]; var target = arguments[0];
var indices = arguments.Skip(1).ToArray(); var indices = arguments.Skip(1).ToArray();
return Push(new LdObj(new LdElema(type, target, indices), type)); return Push(new LdObj(new LdElema(elementType, target, indices), elementType));
} }
throw new NotImplementedException(); Warn("Unknown method called on array type: " + method.Name);
goto default;
default: default:
var call = CallInstruction.Create(opCode, method); var call = CallInstruction.Create(opCode, method);
call.Arguments.AddRange(arguments); call.Arguments.AddRange(arguments);

17
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -60,6 +60,23 @@ namespace ICSharpCode.Decompiler.IL
public string Name { get; set; } public string Name { get; set; }
/// <summary>
/// Gets the scope 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.
/// </remarks>
public ILVariableScope Scope { get; internal set; }
/// <summary>
/// Gets the index of this variable within the <c>VariableScope.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; }
/// <summary> /// <summary>
/// Number of ldloc instructions referencing this variable. /// Number of ldloc instructions referencing this variable.
/// </summary> /// </summary>

2
ICSharpCode.Decompiler/IL/Instructions.cs

@ -442,7 +442,7 @@ namespace ICSharpCode.Decompiler.IL
} }
/// <summary>A container of IL blocks.</summary> /// <summary>A container of IL blocks.</summary>
public sealed partial class ILFunction : ILInstruction public sealed partial class ILFunction : ILVariableScope
{ {
public static readonly SlotInfo BodySlot = new SlotInfo("Body"); public static readonly SlotInfo BodySlot = new SlotInfo("Body");
ILInstruction body; ILInstruction body;

3
ICSharpCode.Decompiler/IL/Instructions.tt

@ -41,7 +41,8 @@
new OpCode("ILFunction", "A container of IL blocks.", new OpCode("ILFunction", "A container of IL blocks.",
CustomChildren(new [] { CustomChildren(new [] {
new ChildInfo("body") new ChildInfo("body")
}), CustomConstructor, CustomWriteTo, CustomComputeFlags, CustomVariableName("function"), ResultType("O")), }), CustomConstructor, CustomWriteTo, CustomComputeFlags, CustomVariableName("function"), ResultType("O")
) { BaseClass = "ILVariableScope" },
new OpCode("BlockContainer", "A container of IL blocks.", new OpCode("BlockContainer", "A container of IL blocks.",
VoidResult, CustomConstructor, CustomVariableName("container")), VoidResult, CustomConstructor, CustomVariableName("container")),
new OpCode("Block", "A block of IL instructions.", new OpCode("Block", "A block of IL instructions.",

4
ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs

@ -110,9 +110,9 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
internal override void CheckInvariant() internal override void CheckInvariant(ILPhase phase)
{ {
base.CheckInvariant(); base.CheckInvariant(phase);
Debug.Assert(CompoundAssignmentType == CompoundAssignmentType.None || IsValidCompoundAssignmentTarget(Left)); Debug.Assert(CompoundAssignmentType == CompoundAssignmentType.None || IsValidCompoundAssignmentTarget(Left));
} }

4
ICSharpCode.Decompiler/IL/Instructions/Block.cs

@ -91,9 +91,9 @@ namespace ICSharpCode.Decompiler.IL
return clone; return clone;
} }
internal override void CheckInvariant() internal override void CheckInvariant(ILPhase phase)
{ {
base.CheckInvariant(); base.CheckInvariant(phase);
for (int i = 0; i < Instructions.Count - 1; i++) { for (int i = 0; i < Instructions.Count - 1; i++) {
// only the last instruction may have an unreachable endpoint // only the last instruction may have an unreachable endpoint
Debug.Assert(!Instructions[i].HasFlag(InstructionFlags.EndPointUnreachable)); Debug.Assert(!Instructions[i].HasFlag(InstructionFlags.EndPointUnreachable));

4
ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs

@ -139,9 +139,9 @@ namespace ICSharpCode.Decompiler.IL
return BlockSlot; return BlockSlot;
} }
internal override void CheckInvariant() internal override void CheckInvariant(ILPhase phase)
{ {
base.CheckInvariant(); base.CheckInvariant(phase);
Debug.Assert(EntryPoint == Blocks[0]); Debug.Assert(EntryPoint == Blocks[0]);
Debug.Assert(!IsConnected || EntryPoint.IncomingEdgeCount >= 1); Debug.Assert(!IsConnected || EntryPoint.IncomingEdgeCount >= 1);
Debug.Assert(Blocks.All(b => b.HasFlag(InstructionFlags.EndPointUnreachable))); Debug.Assert(Blocks.All(b => b.HasFlag(InstructionFlags.EndPointUnreachable)));

10
ICSharpCode.Decompiler/IL/Instructions/Branch.cs

@ -31,10 +31,6 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// When jumping to the entrypoint of the current block container, the branch represents a <c>continue</c> statement. /// When jumping to the entrypoint of the current block container, the branch represents a <c>continue</c> statement.
///
/// Phase-1 execution of a branch is a no-op.
/// Phase-2 execution removes PopCount elements from the evaluation stack
/// and jumps to the target block.
/// </remarks> /// </remarks>
partial class Branch : SimpleInstruction partial class Branch : SimpleInstruction
{ {
@ -92,10 +88,10 @@ namespace ICSharpCode.Decompiler.IL
get { return targetBlock != null ? targetBlock.Label : CecilExtensions.OffsetToString(TargetILOffset); } get { return targetBlock != null ? targetBlock.Label : CecilExtensions.OffsetToString(TargetILOffset); }
} }
internal override void CheckInvariant() internal override void CheckInvariant(ILPhase phase)
{ {
base.CheckInvariant(); base.CheckInvariant(phase);
if (targetBlock != null) { if (phase > ILPhase.InILReader) {
Debug.Assert(targetBlock.Parent is BlockContainer); Debug.Assert(targetBlock.Parent is BlockContainer);
Debug.Assert(this.IsDescendantOf(targetBlock.Parent)); Debug.Assert(this.IsDescendantOf(targetBlock.Parent));
} }

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

@ -26,7 +26,6 @@ namespace ICSharpCode.Decompiler.IL
partial class ILFunction partial class ILFunction
{ {
public readonly MethodDefinition Method; public readonly MethodDefinition Method;
public readonly IList<ILVariable> Variables = new List<ILVariable>();
public ILFunction(MethodDefinition method, ILInstruction body) : base(OpCode.ILFunction) public ILFunction(MethodDefinition method, ILInstruction body) : base(OpCode.ILFunction)
{ {

18
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -27,6 +27,20 @@ using ICSharpCode.Decompiler.CSharp;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
internal enum ILPhase
{
/// <summary>
/// Reading the individual instructions.
/// * Variables don't have scopes yet as the ILFunction is not created yet.
/// * Branches point to IL offsets, not blocks.
/// </summary>
InILReader,
/// <summary>
/// The usual invariants are established.
/// </summary>
Normal,
}
/// <summary> /// <summary>
/// Represents a decoded IL instruction /// Represents a decoded IL instruction
/// </summary> /// </summary>
@ -47,7 +61,7 @@ namespace ICSharpCode.Decompiler.IL
} }
[Conditional("DEBUG")] [Conditional("DEBUG")]
internal virtual void CheckInvariant() internal virtual void CheckInvariant(ILPhase phase)
{ {
foreach (var child in Children) { foreach (var child in Children) {
Debug.Assert(child.Parent == this); Debug.Assert(child.Parent == this);
@ -55,7 +69,7 @@ namespace ICSharpCode.Decompiler.IL
// if child flags are invalid, parent flags must be too // if child flags are invalid, parent flags must be too
Debug.Assert(child.flags != invalidFlags || this.flags == invalidFlags); Debug.Assert(child.flags != invalidFlags || this.flags == invalidFlags);
Debug.Assert(child.IsConnected == this.IsConnected); Debug.Assert(child.IsConnected == this.IsConnected);
child.CheckInvariant(); child.CheckInvariant(phase);
} }
} }

4
ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs

@ -40,9 +40,9 @@ namespace ICSharpCode.Decompiler.IL
this.FalseInst = falseInst ?? new Nop(); this.FalseInst = falseInst ?? new Nop();
} }
internal override void CheckInvariant() internal override void CheckInvariant(ILPhase phase)
{ {
base.CheckInvariant(); base.CheckInvariant(phase);
Debug.Assert(condition.ResultType == StackType.I4); Debug.Assert(condition.ResultType == StackType.I4);
} }

6
ICSharpCode.Decompiler/IL/Instructions/Leave.cs

@ -81,10 +81,10 @@ namespace ICSharpCode.Decompiler.IL
get { return targetContainer != null ? targetContainer.EntryPoint.Label : string.Empty; } get { return targetContainer != null ? targetContainer.EntryPoint.Label : string.Empty; }
} }
internal override void CheckInvariant() internal override void CheckInvariant(ILPhase phase)
{ {
base.CheckInvariant(); base.CheckInvariant(phase);
Debug.Assert(targetContainer == null || this.IsDescendantOf(targetContainer)); Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(targetContainer));
} }
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)

19
ICSharpCode.Decompiler/IL/Instructions/LocalVarInstructions.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Diagnostics;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
@ -33,6 +34,12 @@ namespace ICSharpCode.Decompiler.IL
variable.LoadCount--; variable.LoadCount--;
base.Disconnected(); base.Disconnected();
} }
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Scope));
}
} }
partial class LdLoca partial class LdLoca
@ -48,6 +55,12 @@ namespace ICSharpCode.Decompiler.IL
variable.AddressCount--; variable.AddressCount--;
base.Disconnected(); base.Disconnected();
} }
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Scope));
}
} }
partial class StLoc partial class StLoc
@ -63,5 +76,11 @@ namespace ICSharpCode.Decompiler.IL
variable.StoreCount--; variable.StoreCount--;
base.Disconnected(); base.Disconnected();
} }
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(phase <= ILPhase.InILReader || this.IsDescendantOf(variable.Scope));
}
} }
} }

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

@ -46,8 +46,6 @@ namespace ICSharpCode.Decompiler.IL
/// Try-catch statement. /// Try-catch statement.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// The evaluation stack does not need to be empty when entering or leaving a try-catch-block.
/// All try or catch blocks with reachable endpoint must produce compatible stacks.
/// The return value of the try or catch blocks is ignored, the TryCatch always returns void. /// The return value of the try or catch blocks is ignored, the TryCatch always returns void.
/// </remarks> /// </remarks>
partial class TryCatch : TryInstruction partial class TryCatch : TryInstruction
@ -125,20 +123,19 @@ namespace ICSharpCode.Decompiler.IL
/// ///
/// When an exception occurs in the try block of the parent try.catch statement, the runtime searches /// When an exception occurs in the try block of the parent try.catch statement, the runtime searches
/// the nearest enclosing TryCatchHandler with a matching variable type and /// the nearest enclosing TryCatchHandler with a matching variable type and
/// assigns the exception object to the <see cref="Variable"/>. /// assigns the exception object to the <see cref="Variable"/>, and executes the <see cref="Filter"/>.
/// Then, the evaluation stack is cleared and the <see cref="Filter"/> is executed
/// (first phase-1 execution, which should be a no-op given the empty stack, then phase-2 execution).
/// If the filter evaluates to 0, the exception is not caught and the runtime looks for the next catch handler. /// If the filter evaluates to 0, the exception is not caught and the runtime looks for the next catch handler.
/// If the filter evaluates to 1, the stack is unwound, the exception caught and assigned to the <see cref="Variable"/>, /// If the filter evaluates to 1, the stack is unwound, the exception caught and assigned to the <see cref="Variable"/>,
/// the evaluation stack is cleared again, and the <see cref="Body"/> is executed (again, phase-1 + phase-2). /// and the <see cref="Body"/> is executed.
/// </summary> /// </summary>
partial class TryCatchHandler partial class TryCatchHandler
{ {
internal override void CheckInvariant() internal override void CheckInvariant(ILPhase phase)
{ {
base.CheckInvariant(); base.CheckInvariant(phase);
Debug.Assert(Parent is TryCatch); Debug.Assert(Parent is TryCatch);
Debug.Assert(filter.ResultType == StackType.I4); Debug.Assert(filter.ResultType == StackType.I4);
Debug.Assert(this.IsDescendantOf(variable.Scope));
} }
public override StackType ResultType { public override StackType ResultType {

162
ICSharpCode.Decompiler/IL/Instructions/VariableScope.cs

@ -0,0 +1,162 @@
// Copyright (c) 2016 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
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);
}
}
/// <summary>
/// The collection of variables in a <c>ILVariableScope</c>.
/// </summary>
public class ILVariableCollection : ICollection<ILVariable>, IReadOnlyList<ILVariable>
{
readonly ILVariableScope scope;
readonly List<ILVariable> list = new List<ILVariable>();
internal ILVariableCollection(ILVariableScope scope)
{
this.scope = scope;
}
/// <summary>
/// Gets a variable given its <c>IndexInScope</c>.
/// </summary>
public ILVariable this[int index] {
get {
return list[index];
}
}
public bool Add(ILVariable item)
{
if (item.Scope != null) {
if (item.Scope == scope)
return false;
else
throw new ArgumentException("Variable already belongs to another scope");
}
item.Scope = scope;
item.IndexInScope = list.Count;
list.Add(item);
return true;
}
void ICollection<ILVariable>.Add(ILVariable item)
{
Add(item);
}
public void Clear()
{
foreach (var v in list) {
v.Scope = null;
}
list.Clear();
}
public bool Contains(ILVariable item)
{
Debug.Assert(item.Scope != scope || list[item.IndexInScope] == item);
return item.Scope == scope;
}
public bool Remove(ILVariable item)
{
if (item.Scope != scope)
return false;
Debug.Assert(list[item.IndexInScope] == item);
RemoveAt(item.IndexInScope);
return true;
}
void RemoveAt(int index)
{
// swap-remove index
list[index] = list[list.Count - 1];
list[index].IndexInScope = index;
list.RemoveAt(list.Count - 1);
}
/// <summary>
/// Remove variables that have StoreCount == LoadCount == AddressCount == 0.
/// </summary>
public void RemoveDead()
{
for (int i = 0; i < list.Count;) {
var v = list[i];
if (v.StoreCount == 0 && v.LoadCount == 0 && v.AddressCount == 0) {
RemoveAt(i);
} else {
i++;
}
}
}
public int Count {
get { return list.Count; }
}
public void CopyTo(ILVariable[] array, int arrayIndex)
{
list.CopyTo(array, arrayIndex);
}
bool ICollection<ILVariable>.IsReadOnly {
get { return false; }
}
public List<ILVariable>.Enumerator GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator<ILVariable> IEnumerable<ILVariable>.GetEnumerator()
{
return GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

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

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

Loading…
Cancel
Save