Browse Source

Clarify the meaning of ILVariable.Index

pull/1423/head
Daniel Grunwald 6 years ago
parent
commit
47ca51a769
  1. 3
      ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
  2. 2
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
  3. 11
      ICSharpCode.Decompiler/IL/ILReader.cs
  4. 58
      ICSharpCode.Decompiler/IL/ILVariable.cs
  5. 28
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  6. 7
      ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs
  7. 8
      ICSharpCode.Decompiler/IL/Transforms/DetectCatchWhenConditionBlocks.cs
  8. 2
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  9. 1
      ICSharpCode.Decompiler/IL/Transforms/SplitVariables.cs

3
ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs

@ -286,7 +286,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -286,7 +286,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
switch (kind) {
case VariableKind.PinnedLocal:
case VariableKind.Parameter:
case VariableKind.Exception:
case VariableKind.ExceptionLocal:
case VariableKind.ExceptionStackSlot:
case VariableKind.UsingLocal:
case VariableKind.ForeachLocal:
return false;

2
ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

@ -565,7 +565,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -565,7 +565,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
}
awaitBlocks.Add(block, (awaiterVar, awaiterField));
if (awaiterVar.Index < smallestAwaiterVarIndex) {
smallestAwaiterVarIndex = awaiterVar.Index;
smallestAwaiterVarIndex = awaiterVar.Index.Value;
}
}
}

11
ICSharpCode.Decompiler/IL/ILReader.cs

@ -225,11 +225,6 @@ namespace ICSharpCode.Decompiler.IL @@ -225,11 +225,6 @@ namespace ICSharpCode.Decompiler.IL
ILVariable CreateILVariable(int index, IType parameterType, string name)
{
Debug.Assert(!parameterType.IsUnbound());
if (parameterType.IsUnbound()) {
// parameter types should not be unbound, the only known cause for these is a Cecil bug:
Debug.Assert(index < 0); // cecil bug occurs only for "this"
parameterType = new ParameterizedType(parameterType.GetDefinition(), parameterType.TypeArguments);
}
ITypeDefinition def = parameterType.GetDefinition();
if (def != null && index < 0 && def.IsReferenceType == false) {
parameterType = new ByReferenceType(parameterType);
@ -352,14 +347,14 @@ namespace ICSharpCode.Decompiler.IL @@ -352,14 +347,14 @@ namespace ICSharpCode.Decompiler.IL
ImmutableStack<ILVariable> ehStack = null;
if (eh.Kind == ExceptionRegionKind.Catch) {
var catchType = module.ResolveType(eh.CatchType, genericContext);
var v = new ILVariable(VariableKind.Exception, catchType, eh.HandlerOffset) {
var v = new ILVariable(VariableKind.ExceptionStackSlot, catchType, eh.HandlerOffset) {
Name = "E_" + eh.HandlerOffset,
HasGeneratedName = true
};
variableByExceptionHandler.Add(eh, v);
ehStack = ImmutableStack.Create(v);
} else if (eh.Kind == ExceptionRegionKind.Filter) {
var v = new ILVariable(VariableKind.Exception, compilation.FindType(KnownTypeCode.Object), eh.HandlerOffset) {
var v = new ILVariable(VariableKind.ExceptionStackSlot, compilation.FindType(KnownTypeCode.Object), eh.HandlerOffset) {
Name = "E_" + eh.HandlerOffset,
HasGeneratedName = true
};
@ -1060,7 +1055,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1060,7 +1055,7 @@ namespace ICSharpCode.Decompiler.IL
{
Debug.Assert(inst.ResultType != StackType.Void);
IType type = compilation.FindType(inst.ResultType.ToKnownTypeCode());
var v = new ILVariable(VariableKind.StackSlot, type, inst.ResultType, inst.ILRange.Start);
var v = new ILVariable(VariableKind.StackSlot, type, inst.ResultType);
v.HasGeneratedName = true;
currentStack = currentStack.Push(v);
return new StLoc(v, inst);

58
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -51,9 +51,13 @@ namespace ICSharpCode.Decompiler.IL @@ -51,9 +51,13 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
Parameter,
/// <summary>
/// Variable created for exception handler
/// Variable created for exception handler.
/// </summary>
Exception,
ExceptionStackSlot,
/// <summary>
/// Local variable used in a catch block.
/// </summary>
ExceptionLocal,
/// <summary>
/// Variable created from stack slot.
/// </summary>
@ -96,9 +100,40 @@ namespace ICSharpCode.Decompiler.IL @@ -96,9 +100,40 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>
/// The index of the local variable or parameter (depending on Kind)
///
/// For VariableKinds with "Local" in the name:
/// * if non-null, the Index refers to the LocalVariableSignature.
/// * index may be null for variables that used to be fields (captured by lambda/async)
/// For Parameters, the Index refers to the method's list of parameters.
/// The special "this" parameter has index -1.
/// For ExceptionStackSlot, the index is the IL offset of the exception handler.
/// For other kinds, the index has no meaning, and is usually null.
/// </summary>
public readonly int Index;
public readonly int? Index;
[Conditional("DEBUG")]
internal void CheckInvariant()
{
switch (kind) {
case VariableKind.Local:
case VariableKind.ForeachLocal:
case VariableKind.PinnedLocal:
case VariableKind.UsingLocal:
case VariableKind.ExceptionLocal:
// in range of LocalVariableSignature
Debug.Assert(Index == null || Index >= 0);
break;
case VariableKind.Parameter:
// -1 for the "this" parameter
Debug.Assert(Index >= -1);
Debug.Assert(Function == null || Index < Function.Parameters.Count);
break;
case VariableKind.ExceptionStackSlot:
Debug.Assert(Index >= 0);
break;
}
}
public string Name { get; set; }
public bool HasGeneratedName { get; set; }
@ -268,7 +303,7 @@ namespace ICSharpCode.Decompiler.IL @@ -268,7 +303,7 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public IField StateMachineField;
public ILVariable(VariableKind kind, IType type, int index)
public ILVariable(VariableKind kind, IType type, int? index = null)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
@ -278,9 +313,10 @@ namespace ICSharpCode.Decompiler.IL @@ -278,9 +313,10 @@ namespace ICSharpCode.Decompiler.IL
this.Index = index;
if (kind == VariableKind.Parameter)
this.HasInitialValue = true;
CheckInvariant();
}
public ILVariable(VariableKind kind, IType type, StackType stackType, int index)
public ILVariable(VariableKind kind, IType type, StackType stackType, int? index = null)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
@ -290,8 +326,9 @@ namespace ICSharpCode.Decompiler.IL @@ -290,8 +326,9 @@ namespace ICSharpCode.Decompiler.IL
this.Index = index;
if (kind == VariableKind.Parameter)
this.HasInitialValue = true;
CheckInvariant();
}
public override string ToString()
{
return Name;
@ -309,8 +346,11 @@ namespace ICSharpCode.Decompiler.IL @@ -309,8 +346,11 @@ namespace ICSharpCode.Decompiler.IL
case VariableKind.Parameter:
output.Write("param ");
break;
case VariableKind.Exception:
output.Write("exception ");
case VariableKind.ExceptionLocal:
output.Write("exception local ");
break;
case VariableKind.ExceptionStackSlot:
output.Write("exception stack ");
break;
case VariableKind.StackSlot:
output.Write("stack ");
@ -403,7 +443,7 @@ namespace ICSharpCode.Decompiler.IL @@ -403,7 +443,7 @@ namespace ICSharpCode.Decompiler.IL
return false;
if (x.Kind == VariableKind.StackSlot || y.Kind == VariableKind.StackSlot)
return false;
return x.Function == y.Function && x.Kind == y.Kind && x.Index == y.Index;
return x.Index != null && x.Function == y.Function && x.Kind == y.Kind && x.Index == y.Index;
}
public int GetHashCode(ILVariable obj)

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

@ -98,6 +98,7 @@ namespace ICSharpCode.Decompiler.IL @@ -98,6 +98,7 @@ namespace ICSharpCode.Decompiler.IL
for (int i = 0; i < Variables.Count; i++) {
Debug.Assert(Variables[i].Function == this);
Debug.Assert(Variables[i].IndexInFunction == i);
Variables[i].CheckInvariant();
}
base.CheckInvariant(phase);
}
@ -213,32 +214,13 @@ namespace ICSharpCode.Decompiler.IL @@ -213,32 +214,13 @@ namespace ICSharpCode.Decompiler.IL
}
}
int helperVariableCount;
public ILVariable RegisterVariable(VariableKind kind, IType type, string name = null)
{
int index = Variables.Where(v => v.Kind == kind).MaxOrDefault(v => v.Index, -1) + 1;
var variable = new ILVariable(kind, type, index);
var variable = new ILVariable(kind, type);
if (string.IsNullOrWhiteSpace(name)) {
switch (kind) {
case VariableKind.Local:
case VariableKind.ForeachLocal:
name = "V_";
break;
case VariableKind.Parameter:
name = "P_";
break;
case VariableKind.Exception:
name = "E_";
break;
case VariableKind.StackSlot:
name = "S_";
break;
case VariableKind.InitializerTarget:
name = "I_";
break;
default:
throw new ArgumentOutOfRangeException(nameof(kind));
}
name += index;
name = "I_" + (helperVariableCount++);
variable.HasGeneratedName = true;
}
variable.Name = name;

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

@ -89,7 +89,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -89,7 +89,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// note: the initialization by the caller is the first store -> StoreCount must be 1
return v.IsSingleDefinition;
case VariableKind.StackSlot:
case VariableKind.Exception: // Exception variables are normally generated as well.
case VariableKind.ExceptionStackSlot:
// Variables are be copied only if both they and the target copy variable are generated,
// and if the variable has only a single assignment
return v.IsSingleDefinition && target.Kind == VariableKind.StackSlot;
@ -110,8 +110,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -110,8 +110,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
for (int j = 0; j < uninlinedArgs.Length; j++) {
var arg = copiedExpr.Children[j];
var type = context.TypeSystem.FindType(arg.ResultType.ToKnownTypeCode());
uninlinedArgs[j] = new ILVariable(VariableKind.StackSlot, type, arg.ResultType, arg.ILRange.Start) {
Name = "C_" + arg.ILRange.Start
uninlinedArgs[j] = new ILVariable(VariableKind.StackSlot, type, arg.ResultType) {
Name = "C_" + arg.ILRange.Start,
HasGeneratedName = true,
};
block.Instructions.Insert(i++, new StLoc(uninlinedArgs[j], arg));
}

8
ICSharpCode.Decompiler/IL/Transforms/DetectCatchWhenConditionBlocks.cs

@ -27,7 +27,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -27,7 +27,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
public void Run(ILFunction function, ILTransformContext context)
{
foreach (var catchBlock in function.Descendants.OfType<TryCatchHandler>()) {
if (catchBlock.Filter is BlockContainer container && MatchCatchWhenEntryPoint(container, container.EntryPoint, out var exceptionType, out var exceptionSlot, out var whenConditionBlock)) {
if (catchBlock.Filter is BlockContainer container && MatchCatchWhenEntryPoint(catchBlock.Variable, container, container.EntryPoint, out var exceptionType, out var exceptionSlot, out var whenConditionBlock)) {
// set exceptionType
catchBlock.Variable.Type = exceptionType;
// Block entryPoint (incoming: 1) {
@ -67,7 +67,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -67,7 +67,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// br falseBlock
/// }
/// </summary>
bool MatchCatchWhenEntryPoint(BlockContainer container, Block entryPoint, out IType exceptionType, out ILInstruction exceptionSlot, out Block whenConditionBlock)
bool MatchCatchWhenEntryPoint(ILVariable exceptionVar, BlockContainer container, Block entryPoint, out IType exceptionType, out ILInstruction exceptionSlot, out Block whenConditionBlock)
{
exceptionType = null;
exceptionSlot = null;
@ -81,7 +81,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -81,7 +81,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!entryPoint.Instructions[0].MatchStLoc(out var temp, out var isinst) ||
temp.Kind != VariableKind.StackSlot || !isinst.MatchIsInst(out exceptionSlot, out exceptionType))
return false;
if (!exceptionSlot.MatchLdLoc(out var exceptionVar) || exceptionVar.Kind != VariableKind.Exception)
if (!exceptionSlot.MatchLdLoc(exceptionVar))
return false;
if (!entryPoint.Instructions[1].MatchIfInstruction(out var condition, out var branch))
return false;
@ -103,7 +103,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -103,7 +103,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!left.MatchIsInst(out exceptionSlot, out exceptionType))
return false;
if (!exceptionSlot.MatchLdLoc(out var exceptionVar) || exceptionVar.Kind != VariableKind.Exception)
if (!exceptionSlot.MatchLdLoc(exceptionVar))
return false;
if (right.MatchLdNull()) {
return branch.MatchBranch(out whenConditionBlock);

2
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -613,7 +613,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -613,7 +613,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!exceptionSlotLoad.MatchLdLoc(handler.Variable) || !handler.Variable.IsSingleDefinition || handler.Variable.LoadCount != 1)
return;
handler.Variable = exceptionVar;
exceptionVar.Kind = VariableKind.Exception;
exceptionVar.Kind = VariableKind.ExceptionLocal;
entryPoint.Instructions.RemoveAt(0);
}

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

@ -47,7 +47,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -47,7 +47,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
switch (v.Kind) {
case VariableKind.Local:
case VariableKind.Exception:
foreach (var ldloca in v.AddressInstructions) {
if (DetermineAddressUse(ldloca, ldloca.Variable) == AddressUse.Unknown) {
// If we don't understand how the address is being used,

Loading…
Cancel
Save