Browse Source

Clarify the meaning of ILVariable.Index

pull/1423/head
Daniel Grunwald 7 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
switch (kind) { switch (kind) {
case VariableKind.PinnedLocal: case VariableKind.PinnedLocal:
case VariableKind.Parameter: case VariableKind.Parameter:
case VariableKind.Exception: case VariableKind.ExceptionLocal:
case VariableKind.ExceptionStackSlot:
case VariableKind.UsingLocal: case VariableKind.UsingLocal:
case VariableKind.ForeachLocal: case VariableKind.ForeachLocal:
return false; return false;

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

@ -565,7 +565,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
awaitBlocks.Add(block, (awaiterVar, awaiterField)); awaitBlocks.Add(block, (awaiterVar, awaiterField));
if (awaiterVar.Index < smallestAwaiterVarIndex) { 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
ILVariable CreateILVariable(int index, IType parameterType, string name) ILVariable CreateILVariable(int index, IType parameterType, string name)
{ {
Debug.Assert(!parameterType.IsUnbound()); 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(); ITypeDefinition def = parameterType.GetDefinition();
if (def != null && index < 0 && def.IsReferenceType == false) { if (def != null && index < 0 && def.IsReferenceType == false) {
parameterType = new ByReferenceType(parameterType); parameterType = new ByReferenceType(parameterType);
@ -352,14 +347,14 @@ namespace ICSharpCode.Decompiler.IL
ImmutableStack<ILVariable> ehStack = null; ImmutableStack<ILVariable> ehStack = null;
if (eh.Kind == ExceptionRegionKind.Catch) { if (eh.Kind == ExceptionRegionKind.Catch) {
var catchType = module.ResolveType(eh.CatchType, genericContext); 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, Name = "E_" + eh.HandlerOffset,
HasGeneratedName = true HasGeneratedName = true
}; };
variableByExceptionHandler.Add(eh, v); variableByExceptionHandler.Add(eh, v);
ehStack = ImmutableStack.Create(v); ehStack = ImmutableStack.Create(v);
} else if (eh.Kind == ExceptionRegionKind.Filter) { } 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, Name = "E_" + eh.HandlerOffset,
HasGeneratedName = true HasGeneratedName = true
}; };
@ -1060,7 +1055,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
Debug.Assert(inst.ResultType != StackType.Void); Debug.Assert(inst.ResultType != StackType.Void);
IType type = compilation.FindType(inst.ResultType.ToKnownTypeCode()); 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; v.HasGeneratedName = true;
currentStack = currentStack.Push(v); currentStack = currentStack.Push(v);
return new StLoc(v, inst); return new StLoc(v, inst);

58
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -51,9 +51,13 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
Parameter, Parameter,
/// <summary> /// <summary>
/// Variable created for exception handler /// Variable created for exception handler.
/// </summary> /// </summary>
Exception, ExceptionStackSlot,
/// <summary>
/// Local variable used in a catch block.
/// </summary>
ExceptionLocal,
/// <summary> /// <summary>
/// Variable created from stack slot. /// Variable created from stack slot.
/// </summary> /// </summary>
@ -96,9 +100,40 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// The index of the local variable or parameter (depending on Kind) /// 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> /// </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 string Name { get; set; }
public bool HasGeneratedName { get; set; } public bool HasGeneratedName { get; set; }
@ -268,7 +303,7 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
public IField StateMachineField; public IField StateMachineField;
public ILVariable(VariableKind kind, IType type, int index) public ILVariable(VariableKind kind, IType type, int? index = null)
{ {
if (type == null) if (type == null)
throw new ArgumentNullException(nameof(type)); throw new ArgumentNullException(nameof(type));
@ -278,9 +313,10 @@ namespace ICSharpCode.Decompiler.IL
this.Index = index; this.Index = index;
if (kind == VariableKind.Parameter) if (kind == VariableKind.Parameter)
this.HasInitialValue = true; 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) if (type == null)
throw new ArgumentNullException(nameof(type)); throw new ArgumentNullException(nameof(type));
@ -290,8 +326,9 @@ namespace ICSharpCode.Decompiler.IL
this.Index = index; this.Index = index;
if (kind == VariableKind.Parameter) if (kind == VariableKind.Parameter)
this.HasInitialValue = true; this.HasInitialValue = true;
CheckInvariant();
} }
public override string ToString() public override string ToString()
{ {
return Name; return Name;
@ -309,8 +346,11 @@ namespace ICSharpCode.Decompiler.IL
case VariableKind.Parameter: case VariableKind.Parameter:
output.Write("param "); output.Write("param ");
break; break;
case VariableKind.Exception: case VariableKind.ExceptionLocal:
output.Write("exception "); output.Write("exception local ");
break;
case VariableKind.ExceptionStackSlot:
output.Write("exception stack ");
break; break;
case VariableKind.StackSlot: case VariableKind.StackSlot:
output.Write("stack "); output.Write("stack ");
@ -403,7 +443,7 @@ namespace ICSharpCode.Decompiler.IL
return false; return false;
if (x.Kind == VariableKind.StackSlot || y.Kind == VariableKind.StackSlot) if (x.Kind == VariableKind.StackSlot || y.Kind == VariableKind.StackSlot)
return false; 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) public int GetHashCode(ILVariable obj)

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

@ -98,6 +98,7 @@ namespace ICSharpCode.Decompiler.IL
for (int i = 0; i < Variables.Count; i++) { for (int i = 0; i < Variables.Count; i++) {
Debug.Assert(Variables[i].Function == this); Debug.Assert(Variables[i].Function == this);
Debug.Assert(Variables[i].IndexInFunction == i); Debug.Assert(Variables[i].IndexInFunction == i);
Variables[i].CheckInvariant();
} }
base.CheckInvariant(phase); base.CheckInvariant(phase);
} }
@ -213,32 +214,13 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
int helperVariableCount;
public ILVariable RegisterVariable(VariableKind kind, IType type, string name = null) 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);
var variable = new ILVariable(kind, type, index);
if (string.IsNullOrWhiteSpace(name)) { if (string.IsNullOrWhiteSpace(name)) {
switch (kind) { name = "I_" + (helperVariableCount++);
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;
variable.HasGeneratedName = true; variable.HasGeneratedName = true;
} }
variable.Name = name; variable.Name = name;

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

@ -89,7 +89,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// note: the initialization by the caller is the first store -> StoreCount must be 1 // note: the initialization by the caller is the first store -> StoreCount must be 1
return v.IsSingleDefinition; return v.IsSingleDefinition;
case VariableKind.StackSlot: 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, // Variables are be copied only if both they and the target copy variable are generated,
// and if the variable has only a single assignment // and if the variable has only a single assignment
return v.IsSingleDefinition && target.Kind == VariableKind.StackSlot; return v.IsSingleDefinition && target.Kind == VariableKind.StackSlot;
@ -110,8 +110,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
for (int j = 0; j < uninlinedArgs.Length; j++) { for (int j = 0; j < uninlinedArgs.Length; j++) {
var arg = copiedExpr.Children[j]; var arg = copiedExpr.Children[j];
var type = context.TypeSystem.FindType(arg.ResultType.ToKnownTypeCode()); var type = context.TypeSystem.FindType(arg.ResultType.ToKnownTypeCode());
uninlinedArgs[j] = new ILVariable(VariableKind.StackSlot, type, arg.ResultType, arg.ILRange.Start) { uninlinedArgs[j] = new ILVariable(VariableKind.StackSlot, type, arg.ResultType) {
Name = "C_" + arg.ILRange.Start Name = "C_" + arg.ILRange.Start,
HasGeneratedName = true,
}; };
block.Instructions.Insert(i++, new StLoc(uninlinedArgs[j], arg)); 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
public void Run(ILFunction function, ILTransformContext context) public void Run(ILFunction function, ILTransformContext context)
{ {
foreach (var catchBlock in function.Descendants.OfType<TryCatchHandler>()) { 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 // set exceptionType
catchBlock.Variable.Type = exceptionType; catchBlock.Variable.Type = exceptionType;
// Block entryPoint (incoming: 1) { // Block entryPoint (incoming: 1) {
@ -67,7 +67,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// br falseBlock /// br falseBlock
/// } /// }
/// </summary> /// </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; exceptionType = null;
exceptionSlot = null; exceptionSlot = null;
@ -81,7 +81,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!entryPoint.Instructions[0].MatchStLoc(out var temp, out var isinst) || if (!entryPoint.Instructions[0].MatchStLoc(out var temp, out var isinst) ||
temp.Kind != VariableKind.StackSlot || !isinst.MatchIsInst(out exceptionSlot, out exceptionType)) temp.Kind != VariableKind.StackSlot || !isinst.MatchIsInst(out exceptionSlot, out exceptionType))
return false; return false;
if (!exceptionSlot.MatchLdLoc(out var exceptionVar) || exceptionVar.Kind != VariableKind.Exception) if (!exceptionSlot.MatchLdLoc(exceptionVar))
return false; return false;
if (!entryPoint.Instructions[1].MatchIfInstruction(out var condition, out var branch)) if (!entryPoint.Instructions[1].MatchIfInstruction(out var condition, out var branch))
return false; return false;
@ -103,7 +103,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!left.MatchIsInst(out exceptionSlot, out exceptionType)) if (!left.MatchIsInst(out exceptionSlot, out exceptionType))
return false; return false;
if (!exceptionSlot.MatchLdLoc(out var exceptionVar) || exceptionVar.Kind != VariableKind.Exception) if (!exceptionSlot.MatchLdLoc(exceptionVar))
return false; return false;
if (right.MatchLdNull()) { if (right.MatchLdNull()) {
return branch.MatchBranch(out whenConditionBlock); return branch.MatchBranch(out whenConditionBlock);

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

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

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

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

Loading…
Cancel
Save