Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
173b84d
Add reflection introspection support for function pointers
steveharter May 31, 2022
e546ee2
Fix compiler issue; test MLC to NetFramework
steveharter Jan 23, 2023
36e07d6
Fix compile issue; prep for review
steveharter Jan 23, 2023
e755c1c
Compile issue with MLC under certain conditions
steveharter Jan 23, 2023
b3b64ff
compile issue cont'd; lazy load mods on root
steveharter Jan 23, 2023
3aef789
compile issues cont'd; prepare for review
steveharter Jan 24, 2023
f76c75d
Remove Node back reference; fix edge case test failure
steveharter Jan 24, 2023
73b15b3
Increase test coverage; add missing recursive check
steveharter Jan 24, 2023
1361142
Various feedback; support mods on generic type parameters
steveharter Jan 26, 2023
520a3f5
Merge branch 'main' of https://github.com/steveharter/runtime into Fc…
steveharter Jan 26, 2023
64a987e
Fix MLC edge case; Native AOT test enable\disable
steveharter Jan 26, 2023
5f8a81e
Native AOT test enable\disable; add a generic test
steveharter Jan 26, 2023
2df9d2b
Native AOT test enable\disable; fix missing overload
steveharter Jan 26, 2023
0a6ff32
Add TODOs based on review discussion; MLC field optimization
steveharter Jan 27, 2023
784df92
Merge branch 'main' into FcnPtr
jkotas Feb 1, 2023
8c06d3c
Replace nested signature indices by TypeSignature type
jkotas Jan 31, 2023
f40e506
Move tests into separate classes; other misc non-functional
steveharter Feb 13, 2023
4610e93
Throw NSE for modified type members than may return an unmodified type
steveharter Feb 14, 2023
ca45bd8
Merge branch 'main' of https://github.com/dotnet/runtime into FcnPtr
steveharter Feb 14, 2023
70529f0
Throw NSE on modified type Equals() and GetHashCode()
steveharter Feb 15, 2023
9770a2d
Fix tests for WASI
steveharter Feb 15, 2023
14a9007
Remove unnecessary high overhead tests
steveharter Feb 16, 2023
69ccd75
Merge branch 'main' of https://github.com/dotnet/runtime into FcnPtr
steveharter Feb 16, 2023
f76331c
Fix merge error
steveharter Feb 16, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Move tests into separate classes; other misc non-functional
  • Loading branch information
steveharter committed Feb 13, 2023
commit f40e506fb194cb9ea5d6d3c3c810a637f1558397
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal Type GetTypeParameter(Type unmodifiedType, int index) =>
Create(unmodifiedType, new TypeSignature()
{
_signature = _typeSignature._signature,
_offset = _typeSignature._signature?.GetTypeParameterFromOffset(_typeSignature._offset, index) ?? 0
_offset = _typeSignature._signature?.GetTypeParameterOffset(_typeSignature._offset, index) ?? 0
});

internal SignatureCallingConvention GetCallingConventionFromFunctionPointer() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1641,7 +1641,7 @@ internal Type[] GetCustomModifiers(int parameterIndex, bool required) =>
internal extern int GetParameterOffset(int parameterIndex);

[MethodImpl(MethodImplOptions.InternalCall)]
internal extern int GetTypeParameterFromOffset(int offset, int index);
internal extern int GetTypeParameterOffset(int offset, int index);

[MethodImpl(MethodImplOptions.InternalCall)]
internal extern SignatureCallingConvention GetCallingConventionFromFunctionPointerAtOffset(int offset);
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ FCFuncStart(gSignatureNative)
FCFuncElement("GetSignature", SignatureNative::GetSignature)
FCFuncElement("CompareSig", SignatureNative::CompareSig)
FCFuncElement("GetParameterOffset", SignatureNative::GetParameterOffset)
FCFuncElement("GetTypeParameterFromOffset", SignatureNative::GetTypeParameterFromOffset)
FCFuncElement("GetTypeParameterOffset", SignatureNative::GetTypeParameterOffset)
FCFuncElement("GetCustomModifiersAtOffset", SignatureNative::GetCustomModifiersAtOffset)
FCFuncElement("GetCallingConventionFromFunctionPointerAtOffset", SignatureNative::GetCallingConventionFromFunctionPointerAtOffset)
FCFuncEnd()
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/runtimehandles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1867,7 +1867,7 @@ FCIMPL2(INT32, SignatureNative::GetParameterOffset, SignatureNative* pSignatureU
}
FCIMPLEND

FCIMPL3(INT32, SignatureNative::GetTypeParameterFromOffset, SignatureNative* pSignatureUNSAFE, INT32 offset, INT32 index)
FCIMPL3(INT32, SignatureNative::GetTypeParameterOffset, SignatureNative* pSignatureUNSAFE, INT32 offset, INT32 index)
{
FCALL_CONTRACT;

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/runtimehandles.h
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ class SignatureNative : public Object

static FCDECL2(INT32, GetParameterOffset, SignatureNative* pSig, INT32 parameterIndex);

static FCDECL3(INT32, GetTypeParameterFromOffset, SignatureNative* pSig, INT32 offset, INT32 index);
static FCDECL3(INT32, GetTypeParameterOffset, SignatureNative* pSig, INT32 offset, INT32 index);

static FCDECL2(FC_INT8_RET, GetCallingConventionFromFunctionPointerAtOffset, SignatureNative* pSig, INT32 offset);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@

namespace System.Tests.Types
{
public partial class FunctionPointerTests
public partial class FunctionPointerCallingConventionTests
{
private const BindingFlags Bindings = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;

[Theory]
[InlineData(true)]
[InlineData(false)]
Expand Down Expand Up @@ -166,11 +168,31 @@ public static unsafe void UnmanagedCallConv_PhysicalModifiers_Modified(string me
Assert.Equal(0, returnType.GetRequiredCustomModifiers().Length);
}

public unsafe partial class FunctionPointerHolder
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))]
public static unsafe void GenericTypeParameter()
{
Type holder = typeof(FunctionPointerHolder).Project();
FieldInfo f = holder.GetField(nameof(FunctionPointerHolder._genericType), Bindings);
Type propType = f.FieldType.GetProperty("MyProp").GetModifiedPropertyType();

// Requires skipping past the return parameter metadata in order to get to the metadata for the first parameter.
Type paramType = propType.GetFunctionPointerParameterTypes()[1];
Type[] cc = paramType.GetFunctionPointerCallingConventions();
Assert.Equal(1, cc.Length);
Assert.Equal(typeof(CallConvCdecl).Project(), cc[0]);
}

private unsafe partial class FunctionPointerHolder
{
public delegate* unmanaged[Cdecl, MemberFunction]<int> MethodUnmanagedReturnValue_DifferentCallingConventions1() => default;
public delegate* unmanaged[Stdcall, MemberFunction]<int> MethodUnmanagedReturnValue_DifferentCallingConventions2() => default;

#pragma warning disable 0649
public MyGenericClass<delegate*<int, int, int>[]> _genericType;
#pragma warning restore 0649

// Methods to verify calling conventions and synthesized modopts.
// The non-SuppressGCTransition variants are encoded with the CallKind byte.
// The SuppressGCTransition variants are encoded as modopts (CallKind is "Unmananged").
Expand All @@ -183,6 +205,13 @@ public void MethodCallConv_Thiscall(delegate* unmanaged[Thiscall]<void> f) { }
public void MethodCallConv_Thiscall_SuppressGCTransition(delegate* unmanaged[Thiscall, SuppressGCTransition]<void> f) { }
public void MethodCallConv_Fastcall(delegate* unmanaged[Fastcall]<void> f) { }
public void MethodCallConv_Fastcall_SuppressGCTransition(delegate* unmanaged[Fastcall, SuppressGCTransition]<void> f) { }

public class MyClass { }

public unsafe class MyGenericClass<T>
{
public delegate*<T, delegate* unmanaged[Cdecl]<void>, void> MyProp { get; }
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ namespace System.Tests.Types
// Also see ModifiedTypeTests which tests custom modifiers.
// Unmodified Type instances are cached and keyed by the runtime.
// Modified Type instances are created for each member.
public partial class FunctionPointerTests
public partial class FunctionPointerEqualityTests
{
private const BindingFlags Bindings = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))]
public static unsafe void FunctionUnmanagedPointerReturn_DifferentReturnValue()
public static unsafe void DifferentReturnValue()
{
Type t = typeof(FunctionPointerHolder).Project();

Expand All @@ -34,7 +36,7 @@ public static unsafe void FunctionUnmanagedPointerReturn_DifferentReturnValue()
[InlineData(nameof(FunctionPointerHolder.Field_DateOnly), nameof(FunctionPointerHolder.Field_Int))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))]
public static unsafe void SigEqualityInDifferentModule_Field(string name, string otherName)
public static unsafe void SigInDifferentModule_Field(string name, string otherName)
{
Type fph1 = typeof(FunctionPointerHolder).Project();
Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project();
Expand All @@ -54,7 +56,7 @@ public static unsafe void SigEqualityInDifferentModule_Field(string name, string
[InlineData(nameof(FunctionPointerHolder.Prop_DateOnly), nameof(FunctionPointerHolder.Prop_Int))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))]
public static unsafe void SigEqualityInDifferentModule_Property(string name, string otherName)
public static unsafe void SigInDifferentModule_Property(string name, string otherName)
{
Type fph1 = typeof(FunctionPointerHolder).Project();
Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project();
Expand All @@ -74,7 +76,7 @@ public static unsafe void SigEqualityInDifferentModule_Property(string name, str
[InlineData(nameof(FunctionPointerHolder.MethodReturnValue_DateOnly), nameof(FunctionPointerHolder.MethodReturnValue_Int))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))]
public static unsafe void SigEqualityInDifferentModule_MethodReturn(string name, string otherName)
public static unsafe void SigInDifferentModule_MethodReturn(string name, string otherName)
{
Type fph1 = typeof(FunctionPointerHolder).Project();
Type fph2 = typeof(FunctionPointerHolderSeparateModule).Project();
Expand All @@ -96,7 +98,7 @@ public static unsafe void SigEqualityInDifferentModule_MethodReturn(string name,
[InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl), nameof(FunctionPointerHolder.MethodCallConv_Fastcall))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))]
public static unsafe void CallingConventionIdentity_Unmodified(string methodName1, string methodName2)
public static unsafe void CallingConvention_Unmodified(string methodName1, string methodName2)
{
Type t = typeof(FunctionPointerHolder).Project();
MethodInfo m1 = t.GetMethod(methodName1, Bindings);
Expand All @@ -115,7 +117,7 @@ public static unsafe void CallingConventionIdentity_Unmodified(string methodName
[InlineData(nameof(FunctionPointerHolder.MethodCallConv_Cdecl), nameof(FunctionPointerHolder.MethodCallConv_Fastcall))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71095", TestRuntimes.Mono)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/71883", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))]
public static unsafe void CallingConventionIdentity_Modified(string methodName1, string methodName2)
public static unsafe void CallingConvention_Modified(string methodName1, string methodName2)
{
Type t = typeof(FunctionPointerHolder).Project();
MethodInfo m1 = t.GetMethod(methodName1, Bindings);
Expand All @@ -126,5 +128,30 @@ public static unsafe void CallingConventionIdentity_Modified(string methodName1,

Assert.True(fnPtrType1.IsFunctionPointerNotEqual(fnPtrType2));
}

private unsafe class FunctionPointerHolder
{
#pragma warning disable 0649
public delegate* managed<int> Field_Int;
public delegate* managed<DateOnly> Field_DateOnly; // Verify non-primitive
#pragma warning restore 0649

public delegate* managed<int> Prop_Int { get; }
public delegate* managed<DateOnly> Prop_DateOnly { get; }
public delegate* managed<int> MethodReturnValue_Int() => default;
public delegate* managed<DateOnly> MethodReturnValue_DateOnly() => default;

public delegate* unmanaged<int> MethodUnmanagedReturnValue1() => default;
public delegate* unmanaged<bool> MethodUnmanagedReturnValue2() => default;

// Methods to verify calling conventions and synthesized modopts.
// The non-SuppressGCTransition variants are encoded with the CallKind byte.
// The SuppressGCTransition variants are encoded as modopts (CallKind is "Unmananged").
public void MethodCallConv_Cdecl(delegate* unmanaged[Cdecl]<void> f) { }
public void MethodCallConv_Cdecl_SuppressGCTransition(delegate* unmanaged[Cdecl, SuppressGCTransition]<void> f) { }
public void MethodCallConv_Stdcall(delegate* unmanaged[Stdcall]<void> f) { }
public void MethodCallConv_Thiscall(delegate* unmanaged[Thiscall]<void> f) { }
public void MethodCallConv_Fastcall(delegate* unmanaged[Fastcall]<void> f) { }
}
}
}
13 changes: 4 additions & 9 deletions src/libraries/Common/tests/System/FunctionPointerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,9 @@ private static void VerifyFieldOrProperty(Type fnPtrType, bool isModified)
Assert.Equal<Type>(Type.EmptyTypes, fnPtrType.GetFunctionPointerReturnType().GetRequiredCustomModifiers());
}

public unsafe partial class FunctionPointerHolder
private unsafe class FunctionPointerHolder
{
#pragma warning disable 0649
public delegate*<void> ToString_1;
public delegate*unmanaged<void> ToString_2;
public delegate*<int> ToString_3;
Expand All @@ -292,20 +293,14 @@ public unsafe partial class FunctionPointerHolder
public delegate*<delegate*<int, string>, bool> ToString_9;

public delegate* managed<int> Field_Int;
public delegate* managed<DateOnly> Field_DateOnly; // Verify non-primitive
public delegate* managed<MyClass> Field_MyClass;
#pragma warning restore 0649

public delegate* managed<int> Prop_Int { get; }
public delegate* managed<DateOnly> Prop_DateOnly { get; }
public delegate* managed<MyClass> Prop_MyClass { get; }
public delegate* managed<int> MethodReturnValue_Int() => default;
public delegate* managed<DateOnly> MethodReturnValue_DateOnly() => default;
public delegate* unmanaged<int> MethodUnmanagedReturnValue_Int() => default;
public delegate* unmanaged<DateOnly> MethodUnmanagedReturnValue_DateOnly() => default;

public delegate* managed<int> MethodReturnValue1() => default;
public delegate* managed<int> MethodReturnValue2() => default;
public delegate* unmanaged<int> MethodUnmanagedReturnValue1() => default;
public delegate* unmanaged<bool> MethodUnmanagedReturnValue2() => default;

public delegate* unmanaged[Stdcall, MemberFunction]<string, ref bool*, MyClass, in MyStruct, double> SeveralArguments() => default;
public delegate*<in int, out int, void> RequiredModifiers() => default;
Expand Down
Loading