-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Support function pointer types in System.Reflection.Emit
#119935
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Tagging subscribers to this area: @dotnet/area-system-reflection-emit |
@dotnet-policy-service agree |
I've now added support for unmanaged calling conventions and custom modifiers, altough there are still some limitations which I outlined in the original issue (#111003). Fully supporting all possible variants of function pointer types will require updates of the reflection API, as far as I'm concerned. Still, my implementation should support everything that C# currently supports, which is why I am opening the PR for review. I understand if this PR cannot be merged until there is comprehensive support for the feature, altough in my opinion it is already 90% of the way there in terms of support for real-life scenarios. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds support for function pointer types in System.Reflection.Emit by implementing signature generation for function pointers. The implementation currently supports managed function pointers without custom modifiers (modopt), with unmanaged calling conventions and custom modifiers planned for future work.
Key changes:
- Added function pointer type detection and handling in signature generation
- Implemented calling convention mapping for function pointers
- Added support for custom modifiers on function pointer return types and parameters
src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs
Show resolved
Hide resolved
src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.
src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs
Show resolved
Hide resolved
Could you please add tests as well? |
Done. |
{ | ||
foreach (Type conv in conventions) | ||
{ | ||
if (conv == typeof(CallConvCdecl)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PersistedAssemblyBuilder should not assume that the types are from the runtime reflection type universe. This should match the types by name to handle any type universes.
Here is an example of prior art:
runtime/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs
Lines 460 to 485 in 457c6b7
protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute) | |
{ | |
// Handle pseudo custom attributes | |
switch (con.ReflectedType!.FullName) | |
{ | |
case "System.Runtime.InteropServices.StructLayoutAttribute": | |
ParseStructLayoutAttribute(con, binaryAttribute); | |
return; | |
case "System.Runtime.CompilerServices.SpecialNameAttribute": | |
_attributes |= TypeAttributes.SpecialName; | |
return; | |
case "System.SerializableAttribute": | |
#pragma warning disable SYSLIB0050 // 'TypeAttributes.Serializable' is obsolete: 'Formatter-based serialization is obsolete and should not be used'. | |
_attributes |= TypeAttributes.Serializable; | |
#pragma warning restore SYSLIB0050 | |
return; | |
case "System.Runtime.InteropServices.ComImportAttribute": | |
_attributes |= TypeAttributes.Import; | |
return; | |
case "System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeImportAttribute": | |
_attributes |= TypeAttributes.WindowsRuntime; | |
return; | |
case "System.Security.SuppressUnmanagedCodeSecurityAttribute": // It says has no effect in .NET Core, maybe remove? | |
_attributes |= TypeAttributes.HasSecurity; | |
break; | |
} |
Assert.Contains(paramTypes3[1].GetRequiredCustomModifiers(), t => t.FullName == typeof(InAttribute).FullName); | ||
Assert.Equal(typeof(void).FullName, field3Type.GetFunctionPointerReturnType().FullName); | ||
Type[] callingConventions3 = field3Type.GetFunctionPointerCallingConventions(); | ||
Assert.Contains(callingConventions3, t => t.FullName == typeof(CallConvStdcall).FullName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be useful to have tests that validate one assembly can reference function pointer field in other assembly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. I modified my repro from the original issue and added it as a test.
The new test is failing:
|
// } | ||
|
||
TempFile assembly2Path = TempFile.Create(); | ||
Assembly assembly1FromDisk = Assembly.LoadFile(assembly1Path.Path); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should use TestAssemblyLoadContext
, similar to
Lines 2962 to 2964 in 8f0e8ab
TestAssemblyLoadContext tlc = new TestAssemblyLoadContext(); | |
tlc.LoadFromAssemblyPath(file.Path); | |
Type typeFromDisk = tlc.LoadFromAssemblyPath(file2.Path).GetType("Type2"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in the newest commit.
Hope the test runs now, it worked on my machine™.
This fixes #111003. The current implementation is a work in progress, only managed function pointers with no modopts are supported.
I imagine adding support for unmanaged calling conventions and custom modifiers will be a bit more challenging, since I cannot use
Type.GetFunctionPointerCallingConventions
et al.