Browse Source

Properly support `calli` instruction and its interaction with function pointer types.

pull/2150/head
Daniel Grunwald 5 years ago
parent
commit
3831b42197
  1. 12
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs
  2. 37
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 10
      ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs
  4. 40
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  5. 26
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs
  6. 18
      ICSharpCode.Decompiler/IL/ILReader.cs
  7. 4
      ICSharpCode.Decompiler/IL/ILTypeExtensions.cs
  8. 42
      ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs
  9. 4
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  10. 10
      ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs
  11. 84
      ICSharpCode.Decompiler/TypeSystem/FunctionPointerType.cs
  12. 13
      ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs
  13. 45
      ICSharpCode.Decompiler/TypeSystem/TypeProvider.cs
  14. 3
      ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs
  15. 13
      ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs

12
ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs

@ -47,6 +47,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -47,6 +47,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
internal class FunctionPointersWithRefParams
{
public unsafe delegate*<in byte, ref char, out float, ref readonly int> F1;
public unsafe delegate*<ref char, out float, ref int> F2;
// TODO: re-enable test after https://github.com/dotnet/roslyn/issues/47487 is fixed
//public unsafe int CallF1(byte b, char c, out float f)
//{
// return F1(1, ref c, out f);
//}
public unsafe void CallF2(byte b, char c, out float f)
{
F2(ref c, out f) = b;
}
}
// TODO: the new calling convention syntax isn't yet available in the released Roslyn version

37
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -3888,25 +3888,36 @@ namespace ICSharpCode.Decompiler.CSharp @@ -3888,25 +3888,36 @@ namespace ICSharpCode.Decompiler.CSharp
{
return ErrorExpression("calli with instance method signature not supportd");
}
var ty = new FunctionPointerAstType();
if (inst.CallingConvention != System.Reflection.Metadata.SignatureCallingConvention.Default)
var functionPointer = Translate(inst.FunctionPointer, typeHint: inst.FunctionPointerType);
if (!NormalizeTypeVisitor.TypeErasure.EquivalentTypes(functionPointer.Type, inst.FunctionPointerType))
{
functionPointer = functionPointer.ConvertTo(inst.FunctionPointerType, this);
}
var fpt = (FunctionPointerType)functionPointer.Type.SkipModifiers();
var invocation = new InvocationExpression();
invocation.Target = functionPointer;
foreach (var (argInst, (paramType, paramRefKind)) in inst.Arguments.Zip(fpt.ParameterTypes.Zip(fpt.ParameterReferenceKinds)))
{
ty.CallingConvention = inst.CallingConvention.ToString().ToLowerInvariant();
var arg = Translate(argInst, typeHint: paramType).ConvertTo(paramType, this, allowImplicitConversion: true);
if (paramRefKind != ReferenceKind.None)
{
arg = ChangeDirectionExpressionTo(arg, paramRefKind);
}
invocation.Arguments.Add(arg);
}
foreach (var parameterType in inst.ParameterTypes)
if (fpt.ReturnType.SkipModifiers() is ByReferenceType brt)
{
ty.Parameters.Add(new ParameterDeclaration {
Type = astBuilder.ConvertType(parameterType)
});
var rr = new ResolveResult(brt.ElementType);
return new DirectionExpression(
FieldDirection.Ref,
invocation.WithRR(rr).WithILInstruction(inst)
).WithRR(new ByReferenceResolveResult(rr, ReferenceKind.Ref)).WithoutILInstruction();
}
ty.ReturnType = astBuilder.ConvertType(inst.ReturnType);
var functionPointer = Translate(inst.FunctionPointer);
var invocation = new InvocationExpression(new CastExpression(ty, functionPointer));
foreach (var (arg, paramType) in inst.Arguments.Zip(inst.ParameterTypes))
else
{
invocation.Arguments.Add(Translate(arg, typeHint: paramType).ConvertTo(paramType, this, allowImplicitConversion: true));
return invocation.WithRR(new ResolveResult(fpt.ReturnType)).WithILInstruction(inst);
}
return invocation.WithRR(new ResolveResult(inst.ReturnType)).WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitDeconstructInstruction(DeconstructInstruction inst, TranslationContext context)

10
ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs

@ -341,20 +341,16 @@ namespace ICSharpCode.Decompiler.CSharp @@ -341,20 +341,16 @@ namespace ICSharpCode.Decompiler.CSharp
}
if (sig.GetKind() == StandaloneSignatureKind.Method)
{
MethodSignature<IType> methodSig;
FunctionPointerType fpt;
try
{
methodSig = module.DecodeMethodSignature((StandaloneSignatureHandle)handle, genericContext);
(_, fpt) = module.DecodeMethodSignature((StandaloneSignatureHandle)handle, genericContext);
}
catch (BadImageFormatException)
{
break;
}
CollectNamespacesForTypeReference(methodSig.ReturnType);
foreach (var paramType in methodSig.ParameterTypes)
{
CollectNamespacesForTypeReference(paramType);
}
CollectNamespacesForTypeReference(fpt);
}
break;
}

40
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -311,23 +311,41 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -311,23 +311,41 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
var astType = new FunctionPointerAstType();
for (int i = 0; i < fpt.ParameterTypes.Length; i++)
{
astType.Parameters.Add(new ParameterDeclaration {
ParameterModifier = fpt.ParameterReferenceKinds[i] switch
{
ReferenceKind.In => ParameterModifier.In,
ReferenceKind.Ref => ParameterModifier.Ref,
ReferenceKind.Out => ParameterModifier.Out,
_ => ParameterModifier.None,
},
Type = ConvertType(fpt.ParameterTypes[i])
});
var paramDecl = new ParameterDeclaration();
paramDecl.ParameterModifier = fpt.ParameterReferenceKinds[i] switch
{
ReferenceKind.In => ParameterModifier.In,
ReferenceKind.Ref => ParameterModifier.Ref,
ReferenceKind.Out => ParameterModifier.Out,
_ => ParameterModifier.None,
};
IType parameterType = fpt.ParameterTypes[i];
if (paramDecl.ParameterModifier != ParameterModifier.None && parameterType is ByReferenceType brt)
{
paramDecl.Type = ConvertType(brt.ElementType);
}
else
{
paramDecl.Type = ConvertType(parameterType);
}
astType.Parameters.Add(paramDecl);
}
astType.ReturnType = ConvertType(fpt.ReturnType);
if (fpt.ReturnIsRefReadOnly && astType.ReturnType is ComposedType ct && ct.HasRefSpecifier)
{
ct.HasReadOnlySpecifier = true;
}
return astType;
ITypeDefinition treatedAs = fpt.GetDefinition();
if (treatedAs != null)
{
var result = ConvertTypeHelper(treatedAs);
result.AddChild(new Comment(astType.ToString(), CommentType.MultiLine), Roles.Comment);
return result;
}
else
{
return astType;
}
}
else
{

26
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs

@ -130,12 +130,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -130,12 +130,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var rr = memberReferenceExpression.GetResolveResult();
if (rr != null)
{
if (rr.Type is PointerType)
if (IsPointer(rr.Type))
return true;
if (rr is MemberResolveResult mrr && mrr.Member.ReturnType.Kind == TypeKind.Delegate)
{
var method = mrr.Member.ReturnType.GetDefinition()?.GetDelegateInvokeMethod();
if (method != null && (method.ReturnType is PointerType || method.Parameters.Any(p => p.Type is PointerType)))
if (method != null && (IsPointer(method.ReturnType) || method.Parameters.Any(p => IsPointer(p.Type))))
return true;
}
}
@ -149,12 +149,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -149,12 +149,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var rr = identifierExpression.GetResolveResult();
if (rr != null)
{
if (rr.Type is PointerType)
if (IsPointer(rr.Type))
return true;
if (rr is MemberResolveResult mrr && mrr.Member.ReturnType.Kind == TypeKind.Delegate)
{
var method = mrr.Member.ReturnType.GetDefinition()?.GetDelegateInvokeMethod();
if (method != null && (method.ReturnType is PointerType || method.Parameters.Any(p => p.Type is PointerType)))
if (method != null && (IsPointer(method.ReturnType) || method.Parameters.Any(p => IsPointer(p.Type))))
return true;
}
}
@ -166,7 +166,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -166,7 +166,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
bool result = base.VisitStackAllocExpression(stackAllocExpression);
var rr = stackAllocExpression.GetResolveResult();
if (rr?.Type is PointerType)
if (IsPointer(rr?.Type))
return true;
return result;
}
@ -175,7 +175,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -175,7 +175,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
bool result = base.VisitInvocationExpression(invocationExpression);
var rr = invocationExpression.GetResolveResult();
if (rr != null && rr.Type is PointerType)
if (IsPointer(rr?.Type))
return true;
return result;
}
@ -185,5 +185,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -185,5 +185,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
base.VisitFixedVariableInitializer(fixedVariableInitializer);
return true;
}
private bool IsPointer(IType type)
{
switch (type?.Kind)
{
case TypeKind.Pointer:
case TypeKind.FunctionPointer:
return true;
case TypeKind.ByReference:
return IsPointer(((ByReferenceType)type).ElementType);
default:
return false;
}
}
}
}

18
ICSharpCode.Decompiler/IL/ILReader.cs

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

4
ICSharpCode.Decompiler/IL/ILTypeExtensions.cs

@ -16,8 +16,6 @@ @@ -16,8 +16,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Reflection.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL
@ -163,7 +161,7 @@ namespace ICSharpCode.Decompiler.IL @@ -163,7 +161,7 @@ namespace ICSharpCode.Decompiler.IL
case CallVirt callVirt:
return callVirt.Method.ReturnType;
case CallIndirect calli:
return calli.ReturnType;
return calli.FunctionPointerType.ReturnType;
case UserDefinedLogicOperator logicOp:
return logicOp.Method.ReturnType;
case LdObj ldobj:

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

@ -16,9 +16,7 @@ @@ -16,9 +16,7 @@
// 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.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
@ -37,17 +35,8 @@ namespace ICSharpCode.Decompiler.IL @@ -37,17 +35,8 @@ namespace ICSharpCode.Decompiler.IL
public readonly InstructionCollection<ILInstruction> Arguments;
public bool IsInstance { get; }
public bool HasExplicitThis { get; }
public System.Reflection.Metadata.SignatureCallingConvention CallingConvention { get; }
public IType ReturnType { get; }
public ImmutableArray<IType> ParameterTypes { get; }
/// <summary>
/// A 'final instruction' that gets executed after the <c>Instructions</c> collection.
/// Provides the return value for the block.
/// </summary>
/// <remarks>
/// Blocks in containers must have 'Nop' as a final instruction.
/// </remarks>
public FunctionPointerType FunctionPointerType { get; }
public ILInstruction FunctionPointer {
get {
return functionPointer;
@ -58,14 +47,12 @@ namespace ICSharpCode.Decompiler.IL @@ -58,14 +47,12 @@ namespace ICSharpCode.Decompiler.IL
}
}
public CallIndirect(bool isInstance, bool hasExplicitThis, System.Reflection.Metadata.SignatureCallingConvention callingConvention, IType returnType, ImmutableArray<IType> parameterTypes,
public CallIndirect(bool isInstance, bool hasExplicitThis, FunctionPointerType functionPointerType,
ILInstruction functionPointer, IEnumerable<ILInstruction> arguments) : base(OpCode.CallIndirect)
{
this.IsInstance = isInstance;
this.HasExplicitThis = hasExplicitThis;
this.CallingConvention = callingConvention;
this.ReturnType = returnType ?? throw new ArgumentNullException(nameof(returnType));
this.ParameterTypes = parameterTypes.ToImmutableArray();
this.FunctionPointerType = functionPointerType;
this.FunctionPointer = functionPointer;
this.Arguments = new InstructionCollection<ILInstruction>(this, 1);
this.Arguments.AddRange(arguments);
@ -73,24 +60,24 @@ namespace ICSharpCode.Decompiler.IL @@ -73,24 +60,24 @@ namespace ICSharpCode.Decompiler.IL
public override ILInstruction Clone()
{
return new CallIndirect(IsInstance, HasExplicitThis, CallingConvention, ReturnType, ParameterTypes,
return new CallIndirect(IsInstance, HasExplicitThis, FunctionPointerType,
functionPointer.Clone(), this.Arguments.Select(inst => inst.Clone())
).WithILRange(this);
}
public override StackType ResultType => ReturnType.GetStackType();
public override StackType ResultType => FunctionPointerType.ReturnType.GetStackType();
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(Arguments.Count == ParameterTypes.Length + (IsInstance ? 1 : 0));
Debug.Assert(Arguments.Count == FunctionPointerType.ParameterTypes.Length + (IsInstance ? 1 : 0));
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
WriteILRange(output, options);
output.Write("call.indirect ");
ReturnType.WriteTo(output);
FunctionPointerType.ReturnType.WriteTo(output);
output.Write('(');
functionPointer.WriteTo(output, options);
int firstArgument = IsInstance ? 1 : 0;
@ -99,7 +86,7 @@ namespace ICSharpCode.Decompiler.IL @@ -99,7 +86,7 @@ namespace ICSharpCode.Decompiler.IL
output.Write(", ");
Arguments[0].WriteTo(output, options);
}
foreach (var (inst, type) in Arguments.Zip(ParameterTypes, (a, b) => (a, b)))
foreach (var (inst, type) in Arguments.Zip(FunctionPointerType.ParameterTypes, (a, b) => (a, b)))
{
output.Write(", ");
inst.WriteTo(output, options);
@ -161,16 +148,7 @@ namespace ICSharpCode.Decompiler.IL @@ -161,16 +148,7 @@ namespace ICSharpCode.Decompiler.IL
return false;
if (HasExplicitThis != other.HasExplicitThis)
return false;
if (CallingConvention != other.CallingConvention)
return false;
if (ParameterTypes.Length != other.ParameterTypes.Length)
return false;
for (int i = 0; i < ParameterTypes.Length; i++)
{
if (!ParameterTypes[i].Equals(other.ParameterTypes[i]))
return false;
}
return ReturnType.Equals(other.ReturnType);
return FunctionPointerType.Equals(other.FunctionPointerType);
}
}
}

4
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -459,6 +459,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -459,6 +459,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return ldloc.Variable.IsRefReadOnly;
case Call call:
return call.Method.ReturnTypeIsRefReadOnly;
case CallIndirect calli:
return calli.FunctionPointerType.ReturnIsRefReadOnly;
case AddressOf _:
// C# doesn't allow mutation of value-type temporaries
return true;
@ -557,6 +559,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -557,6 +559,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
break;
case OpCode.CallIndirect when loadInst.SlotInfo == CallIndirect.FunctionPointerSlot:
return true;
case OpCode.LdElema:
if (((LdElema)parent).WithSystemIndex)
{

10
ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs

@ -333,9 +333,9 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -333,9 +333,9 @@ namespace ICSharpCode.Decompiler.TypeSystem
dynamicTypeIndex += type.ParameterReferenceKinds[i] switch
{
ReferenceKind.None => 1,
ReferenceKind.Ref => 2,
ReferenceKind.Out => 3,
ReferenceKind.In => 3,
ReferenceKind.Ref => 1,
ReferenceKind.Out => 2, // in/out also count the modreq
ReferenceKind.In => 2,
_ => throw new NotSupportedException()
};
parameters[i] = type.ParameterTypes[i].AcceptVisitor(this);
@ -343,9 +343,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -343,9 +343,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
if (!changed)
return type;
return new FunctionPointerType(type.CallingConvention,
returnType, type.ReturnIsRefReadOnly,
parameters.ToImmutableArray(), type.ParameterReferenceKinds);
return type.WithSignature(returnType, parameters.ToImmutableArray());
}
public override IType VisitTypeDefinition(ITypeDefinition type)

84
ICSharpCode.Decompiler/TypeSystem/FunctionPointerType.cs

@ -23,21 +23,70 @@ using System.Linq; @@ -23,21 +23,70 @@ using System.Linq;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.TypeSystem
{
public class FunctionPointerType : AbstractType
{
public static FunctionPointerType FromSignature(MethodSignature<IType> signature, MetadataModule module)
{
IType returnType = signature.ReturnType;
bool returnIsRefReadOnly = false;
if (returnType is ModifiedType modReturn && modReturn.Modifier.IsKnownType(KnownAttribute.In))
{
returnType = modReturn.ElementType;
returnIsRefReadOnly = true;
}
var parameterTypes = ImmutableArray.CreateBuilder<IType>(signature.ParameterTypes.Length);
var parameterReferenceKinds = ImmutableArray.CreateBuilder<ReferenceKind>(signature.ParameterTypes.Length);
foreach (var p in signature.ParameterTypes)
{
IType paramType = p;
ReferenceKind kind = ReferenceKind.None;
if (p is ModifiedType modreq)
{
if (modreq.Modifier.IsKnownType(KnownAttribute.In))
{
kind = ReferenceKind.In;
paramType = modreq.ElementType;
}
else if (modreq.Modifier.IsKnownType(KnownAttribute.Out))
{
kind = ReferenceKind.Out;
paramType = modreq.ElementType;
}
}
if (paramType.Kind == TypeKind.ByReference)
{
if (kind == ReferenceKind.None)
kind = ReferenceKind.Ref;
}
else
{
kind = ReferenceKind.None;
}
parameterTypes.Add(paramType);
parameterReferenceKinds.Add(kind);
}
return new FunctionPointerType(
module, signature.Header.CallingConvention,
returnType, returnIsRefReadOnly,
parameterTypes.MoveToImmutable(), parameterReferenceKinds.MoveToImmutable());
}
private readonly MetadataModule module;
public readonly SignatureCallingConvention CallingConvention;
public readonly IType ReturnType;
public readonly bool ReturnIsRefReadOnly;
public readonly ImmutableArray<IType> ParameterTypes;
public readonly ImmutableArray<ReferenceKind> ParameterReferenceKinds;
public FunctionPointerType(SignatureCallingConvention callingConvention,
public FunctionPointerType(MetadataModule module, SignatureCallingConvention callingConvention,
IType returnType, bool returnIsRefReadOnly,
ImmutableArray<IType> parameterTypes, ImmutableArray<ReferenceKind> parameterReferenceKinds)
{
this.module = module;
this.CallingConvention = callingConvention;
this.ReturnType = returnType;
this.ReturnIsRefReadOnly = returnIsRefReadOnly;
@ -50,7 +99,21 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -50,7 +99,21 @@ namespace ICSharpCode.Decompiler.TypeSystem
public override bool? IsReferenceType => false;
public override TypeKind Kind => TypeKind.FunctionPointer;
public override TypeKind Kind => ((module.TypeSystemOptions & TypeSystemOptions.FunctionPointers) != 0) ? TypeKind.FunctionPointer : TypeKind.Struct;
public override ITypeDefinition GetDefinition()
{
if ((module.TypeSystemOptions & TypeSystemOptions.FunctionPointers) != 0)
{
return null;
}
else
{
// If FunctionPointers are not enabled in the TS, we still use FunctionPointerType instances;
// but have them act as if they were aliases for UIntPtr.
return module.Compilation.FindType(KnownTypeCode.UIntPtr).GetDefinition();
}
}
public override IType AcceptVisitor(TypeVisitor visitor)
{
@ -82,7 +145,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -82,7 +145,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
if (pt == null)
return this;
else
return new FunctionPointerType(CallingConvention,
return new FunctionPointerType(
module, CallingConvention,
r, ReturnIsRefReadOnly,
pt != null ? pt.ToImmutableArray() : ParameterTypes,
ParameterReferenceKinds);
@ -90,7 +154,9 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -90,7 +154,9 @@ namespace ICSharpCode.Decompiler.TypeSystem
public override bool Equals(IType other)
{
return other is FunctionPointerType fpt && ReturnType.Equals(fpt.ReturnType)
return other is FunctionPointerType fpt
&& CallingConvention == fpt.CallingConvention
&& ReturnType.Equals(fpt.ReturnType)
&& ReturnIsRefReadOnly == fpt.ReturnIsRefReadOnly
&& ParameterTypes.SequenceEqual(fpt.ParameterTypes)
&& ParameterReferenceKinds.SequenceEqual(fpt.ParameterReferenceKinds);
@ -101,13 +167,19 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -101,13 +167,19 @@ namespace ICSharpCode.Decompiler.TypeSystem
unchecked
{
int hash = ReturnType.GetHashCode();
foreach (var p in ParameterTypes)
foreach (var (p, k) in ParameterTypes.Zip(ParameterReferenceKinds))
{
hash ^= p.GetHashCode();
hash ^= p.GetHashCode() ^ k.GetHashCode();
hash *= 8310859;
}
return hash;
}
}
internal IType WithSignature(IType returnType, ImmutableArray<IType> parameterTypes)
{
return new FunctionPointerType(this.module, this.CallingConvention, returnType,
this.ReturnIsRefReadOnly, parameterTypes, this.ParameterReferenceKinds);
}
}
}

13
ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs

@ -689,21 +689,14 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -689,21 +689,14 @@ namespace ICSharpCode.Decompiler.TypeSystem
#endregion
#region Decode Standalone Signature
public MethodSignature<IType> DecodeMethodSignature(StandaloneSignatureHandle handle, GenericContext genericContext)
public (SignatureHeader, FunctionPointerType) DecodeMethodSignature(StandaloneSignatureHandle handle, GenericContext genericContext)
{
var standaloneSignature = metadata.GetStandaloneSignature(handle);
if (standaloneSignature.GetKind() != StandaloneSignatureKind.Method)
throw new BadImageFormatException("Expected Method signature");
var sig = standaloneSignature.DecodeMethodSignature(TypeProvider, genericContext);
return new MethodSignature<IType>(
sig.Header,
IntroduceTupleTypes(sig.ReturnType),
sig.RequiredParameterCount,
sig.GenericParameterCount,
ImmutableArray.CreateRange(
sig.ParameterTypes, IntroduceTupleTypes
)
);
var fpt = FunctionPointerType.FromSignature(sig, this);
return (sig.Header, (FunctionPointerType)IntroduceTupleTypes(fpt));
}
public ImmutableArray<IType> DecodeLocalSignature(StandaloneSignatureHandle handle, GenericContext genericContext)

45
ICSharpCode.Decompiler/TypeSystem/TypeProvider.cs

@ -62,55 +62,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -62,55 +62,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
public IType GetFunctionPointerType(SRM.MethodSignature<IType> signature)
{
if ((module.TypeSystemOptions & TypeSystemOptions.FunctionPointers) == 0)
return compilation.FindType(KnownTypeCode.IntPtr);
if (signature.Header.IsInstance)
{
// pointers to member functions are not supported even in C# 9
return compilation.FindType(KnownTypeCode.IntPtr);
}
IType returnType = signature.ReturnType;
bool returnIsRefReadOnly = false;
if (returnType is ModifiedType modReturn && modReturn.Modifier.IsKnownType(KnownAttribute.In))
{
returnType = modReturn.ElementType;
returnIsRefReadOnly = true;
}
var parameterTypes = ImmutableArray.CreateBuilder<IType>(signature.ParameterTypes.Length);
var parameterReferenceKinds = ImmutableArray.CreateBuilder<ReferenceKind>(signature.ParameterTypes.Length);
foreach (var p in signature.ParameterTypes)
{
IType paramType = p;
ReferenceKind kind = ReferenceKind.None;
if (p is ModifiedType modreq)
{
if (modreq.Modifier.IsKnownType(KnownAttribute.In))
{
kind = ReferenceKind.In;
paramType = modreq.ElementType;
}
else if (modreq.Modifier.IsKnownType(KnownAttribute.Out))
{
kind = ReferenceKind.Out;
paramType = modreq.ElementType;
}
}
if (paramType is ByReferenceType brt)
{
paramType = brt.ElementType;
if (kind == ReferenceKind.None)
kind = ReferenceKind.Ref;
}
else
{
kind = ReferenceKind.None;
}
parameterTypes.Add(paramType);
parameterReferenceKinds.Add(kind);
}
return new FunctionPointerType(signature.Header.CallingConvention,
returnType, returnIsRefReadOnly,
parameterTypes.MoveToImmutable(), parameterReferenceKinds.MoveToImmutable());
return FunctionPointerType.FromSignature(signature, module);
}
public IType GetGenericInstantiation(IType genericType, ImmutableArray<IType> typeArguments)

3
ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs

@ -273,6 +273,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -273,6 +273,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
case TypeKind.Pointer:
case TypeKind.NInt:
case TypeKind.NUInt:
case TypeKind.FunctionPointer:
return StackType.I;
case TypeKind.TypeParameter:
// Type parameters are always considered StackType.O, even
@ -340,6 +341,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -340,6 +341,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
case TypeKind.Pointer:
case TypeKind.NUInt:
case TypeKind.FunctionPointer:
return Sign.Unsigned;
case TypeKind.NInt:
return Sign.Signed;
@ -421,6 +423,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -421,6 +423,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
case TypeKind.ByReference:
return PrimitiveType.Ref;
case TypeKind.NInt:
case TypeKind.FunctionPointer:
return PrimitiveType.I;
case TypeKind.NUInt:
return PrimitiveType.U;

13
ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs

@ -16,13 +16,9 @@ @@ -16,13 +16,9 @@
// 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.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler;
@ -266,13 +262,8 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -266,13 +262,8 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
break;
case HandleKind.StandaloneSignature:
var signature = module.DecodeMethodSignature((StandaloneSignatureHandle)member, genericContext);
foreach (var type in signature.ParameterTypes)
{
type.AcceptVisitor(visitor);
}
signature.ReturnType.AcceptVisitor(visitor);
var (_, fpt) = module.DecodeMethodSignature((StandaloneSignatureHandle)member, genericContext);
fpt.AcceptVisitor(visitor);
if (visitor.Found)
return;

Loading…
Cancel
Save