Browse Source

#1083: Add ArgumentToParameterMap to CallInstruction, in ILAst output call arguments are now prefixed with the parameter index they correspond to, if the mapping is different from the default.

pull/1600/head
Siegfried Pammer 7 years ago
parent
commit
60ace84f26
  1. 36
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs

36
ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs

@ -18,8 +18,10 @@ @@ -18,8 +18,10 @@
using System;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL
{
@ -58,10 +60,21 @@ namespace ICSharpCode.Decompiler.IL @@ -58,10 +60,21 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public bool ILStackWasEmpty;
/// <summary>
/// Gets the mapping of arguments to method parameters. Must be a 1-to-1 mapping.
/// Normally this is index == value for static calls and newobj, and value + 1 == index for instance method calls.
/// |ArgumentToParameterMap| == |Arguments|.
/// </summary>
public int[] ArgumentToParameterMap;
protected CallInstruction(OpCode opCode, IMethod method) : base(opCode)
{
Debug.Assert(method != null);
this.Method = method;
int firstParameter = OpCode != OpCode.NewObj && !Method.IsStatic ? 1 : 0;
this.ArgumentToParameterMap = new int[method.Parameters.Count + firstParameter];
for (int i = 0; i < ArgumentToParameterMap.Length; i++)
ArgumentToParameterMap[i] = -firstParameter + i;
this.Arguments = new InstructionCollection<ILInstruction>(this, 0);
}
@ -113,13 +126,24 @@ namespace ICSharpCode.Decompiler.IL @@ -113,13 +126,24 @@ namespace ICSharpCode.Decompiler.IL
base.CheckInvariant(phase);
int firstArgument = (OpCode != OpCode.NewObj && !Method.IsStatic) ? 1 : 0;
Debug.Assert(Method.Parameters.Count + firstArgument == Arguments.Count);
Debug.Assert(Method.Parameters.Count + firstArgument == ArgumentToParameterMap.Length);
if (firstArgument == 1) {
Debug.Assert(Arguments[0].ResultType == ExpectedTypeForThisPointer(ConstrainedTo ?? Method.DeclaringType),
$"Stack type mismatch in 'this' argument in call to {Method.Name}()");
Debug.Assert(ArgumentToParameterMap[0] == -1, "'this' argument must always be mapped at position 0");
}
for (int i = 0; i < Method.Parameters.Count; ++i) {
Debug.Assert(Arguments[firstArgument + i].ResultType == Method.Parameters[i].Type.GetStackType(),
$"Stack type mismatch in parameter {i} in call to {Method.Name}()");
int paramCount = Method.Parameters.Count;
if (paramCount > 0) {
BitSet bitSet = new BitSet(paramCount);
for (int i = 0; i < paramCount; ++i) {
int mappedTo = ArgumentToParameterMap[firstArgument + i];
Debug.Assert(mappedTo >= 0 && mappedTo < paramCount, $"mapping out of [0..{paramCount}[, was: {mappedTo}");
Debug.Assert(!bitSet[mappedTo], $"argument {mappedTo} is already mapped to a different parameter");
bitSet.Set(mappedTo);
Debug.Assert(Arguments[firstArgument + i].ResultType == Method.Parameters[mappedTo].Type.GetStackType(),
$"Stack type mismatch in parameter {mappedTo} (argument {firstArgument + i}) in call to {Method.Name}()");
}
Debug.Assert(bitSet.All(0, paramCount - 1), "Not all arguments are mapped to a parameter");
}
}
@ -137,9 +161,12 @@ namespace ICSharpCode.Decompiler.IL @@ -137,9 +161,12 @@ namespace ICSharpCode.Decompiler.IL
output.Write(' ');
Method.WriteTo(output);
output.Write('(');
int firstIndex = (OpCode != OpCode.NewObj && !Method.IsStatic) ? -1 : 0;
for (int i = 0; i < Arguments.Count; i++) {
if (i > 0)
output.Write(", ");
if (ArgumentToParameterMap[i] != firstIndex + i)
output.Write($"{ArgumentToParameterMap[i]}: ");
Arguments[i].WriteTo(output, options);
}
output.Write(')');
@ -150,7 +177,8 @@ namespace ICSharpCode.Decompiler.IL @@ -150,7 +177,8 @@ namespace ICSharpCode.Decompiler.IL
CallInstruction o = other as CallInstruction;
return o != null && this.OpCode == o.OpCode && this.Method.Equals(o.Method) && this.IsTail == o.IsTail
&& object.Equals(this.ConstrainedTo, o.ConstrainedTo)
&& Patterns.ListMatch.DoMatch(this.Arguments, o.Arguments, ref match);
&& Patterns.ListMatch.DoMatch(this.Arguments, o.Arguments, ref match)
&& ArgumentToParameterMap.SequenceEqual(o.ArgumentToParameterMap);
}
}

Loading…
Cancel
Save