Browse Source

Fix #1373, fix #1541: add support for instance calls to CallIndirect.

pull/1596/head
Siegfried Pammer 7 years ago
parent
commit
d50b8d66d1
  1. 11
      ICSharpCode.Decompiler/IL/ILReader.cs
  2. 22
      ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs

11
ICSharpCode.Decompiler/IL/ILReader.cs

@ -1401,12 +1401,17 @@ namespace ICSharpCode.Decompiler.IL
var signatureHandle = (StandaloneSignatureHandle)ReadAndDecodeMetadataToken(); var signatureHandle = (StandaloneSignatureHandle)ReadAndDecodeMetadataToken();
var signature = module.DecodeMethodSignature(signatureHandle, genericContext); var signature = module.DecodeMethodSignature(signatureHandle, genericContext);
var functionPointer = Pop(StackType.I); var functionPointer = Pop(StackType.I);
Debug.Assert(!signature.Header.IsInstance); int firstArgument = signature.Header.IsInstance ? 1 : 0;
var arguments = new ILInstruction[signature.ParameterTypes.Length]; var arguments = new ILInstruction[firstArgument + signature.ParameterTypes.Length];
for (int i = signature.ParameterTypes.Length - 1; i >= 0; i--) { for (int i = signature.ParameterTypes.Length - 1; i >= 0; i--) {
arguments[i] = Pop(signature.ParameterTypes[i].GetStackType()); arguments[firstArgument + i] = Pop(signature.ParameterTypes[i].GetStackType());
}
if (firstArgument == 1) {
arguments[0] = Pop();
} }
var call = new CallIndirect( var call = new CallIndirect(
signature.Header.IsInstance,
signature.Header.HasExplicitThis,
signature.Header.CallingConvention, signature.Header.CallingConvention,
signature.ReturnType, signature.ReturnType,
signature.ParameterTypes, signature.ParameterTypes,

22
ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs

@ -32,7 +32,8 @@ namespace ICSharpCode.Decompiler.IL
public readonly InstructionCollection<ILInstruction> Arguments; public readonly InstructionCollection<ILInstruction> Arguments;
ILInstruction functionPointer; ILInstruction functionPointer;
public bool IsInstance { get; }
public bool HasExplicitThis { get; }
public System.Reflection.Metadata.SignatureCallingConvention CallingConvention { get; } public System.Reflection.Metadata.SignatureCallingConvention CallingConvention { get; }
public IType ReturnType { get; } public IType ReturnType { get; }
public ImmutableArray<IType> ParameterTypes { get; } public ImmutableArray<IType> ParameterTypes { get; }
@ -61,9 +62,11 @@ namespace ICSharpCode.Decompiler.IL
functionPointer.ChildIndex = Arguments.Count; functionPointer.ChildIndex = Arguments.Count;
} }
public CallIndirect(System.Reflection.Metadata.SignatureCallingConvention callingConvention, IType returnType, ImmutableArray<IType> parameterTypes, public CallIndirect(bool isInstance, bool hasExplicitThis, System.Reflection.Metadata.SignatureCallingConvention callingConvention, IType returnType, ImmutableArray<IType> parameterTypes,
IEnumerable<ILInstruction> arguments, ILInstruction functionPointer) : base(OpCode.CallIndirect) IEnumerable<ILInstruction> arguments, ILInstruction functionPointer) : base(OpCode.CallIndirect)
{ {
this.IsInstance = isInstance;
this.HasExplicitThis = hasExplicitThis;
this.CallingConvention = callingConvention; this.CallingConvention = callingConvention;
this.ReturnType = returnType ?? throw new ArgumentNullException("returnType"); this.ReturnType = returnType ?? throw new ArgumentNullException("returnType");
this.ParameterTypes = parameterTypes.ToImmutableArray(); this.ParameterTypes = parameterTypes.ToImmutableArray();
@ -74,7 +77,7 @@ namespace ICSharpCode.Decompiler.IL
public override ILInstruction Clone() public override ILInstruction Clone()
{ {
return new CallIndirect(CallingConvention, ReturnType, ParameterTypes, return new CallIndirect(IsInstance, HasExplicitThis, CallingConvention, ReturnType, ParameterTypes,
this.Arguments.Select(inst => inst.Clone()), functionPointer.Clone() this.Arguments.Select(inst => inst.Clone()), functionPointer.Clone()
).WithILRange(this); ).WithILRange(this);
} }
@ -84,7 +87,7 @@ namespace ICSharpCode.Decompiler.IL
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase);
Debug.Assert(Arguments.Count == ParameterTypes.Length); Debug.Assert(Arguments.Count == ParameterTypes.Length + (IsInstance ? 1 : 0));
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
@ -94,7 +97,12 @@ namespace ICSharpCode.Decompiler.IL
ReturnType.WriteTo(output); ReturnType.WriteTo(output);
output.Write('('); output.Write('(');
bool first = true; bool first = true;
foreach (var (inst, type) in Arguments.Zip(ParameterTypes, (a,b) => (a,b))) { int firstArgument = IsInstance ? 1 : 0;
if (firstArgument == 1) {
Arguments[0].WriteTo(output, options);
first = false;
}
foreach (var (inst, type) in Arguments.Skip(firstArgument).Zip(ParameterTypes, (a,b) => (a,b))) {
if (first) if (first)
first = false; first = false;
else else
@ -155,6 +163,10 @@ namespace ICSharpCode.Decompiler.IL
bool EqualSignature(CallIndirect other) bool EqualSignature(CallIndirect other)
{ {
if (IsInstance != other.IsInstance)
return false;
if (HasExplicitThis != other.HasExplicitThis)
return false;
if (CallingConvention != other.CallingConvention) if (CallingConvention != other.CallingConvention)
return false; return false;
if (ParameterTypes.Length != other.ParameterTypes.Length) if (ParameterTypes.Length != other.ParameterTypes.Length)

Loading…
Cancel
Save