Open MichalPetryka opened 10 months ago
Tagging subscribers to this area: @dotnet/area-system-runtime See info in area-owners.md if you want to be subscribed.
Author: | MichalPetryka |
---|---|
Assignees: | - |
Labels: | `api-suggestion`, `area-System.Runtime`, `untriaged` |
Milestone: | - |
Exposing the hidden pointer constructor on delegates, this however would not suggest that such operation is unsafe.
The hidden constructor is exposed via UnsafeAccessor that makes it clear that it is an unsafe operation. For example:
using System.Runtime.CompilerServices;
unsafe
{
IntPtr p = (IntPtr)(delegate* <void>)&Hello;
MyDelegate d = ConstructMyDelegate(null, p);
d();
}
[UnsafeAccessor(UnsafeAccessorKind.Constructor)]
extern static MyDelegate ConstructMyDelegate(object o, IntPtr p);
static void Hello()
{
Console.WriteLine("Hello world");
}
delegate void MyDelegate();
NativeAOT doesn't fully implement the constructor for it.
This constructor is reflection heavy operation. It needs to convert the pointer back to MethodInfo, find the signature of the MethodInfo, compare it with the signature of the delegate, and then compute the set of wrappers and thunks to convert the call with one signature to the call with the other signature. It can be all implemented in native AOT, but I suspect that it would require preserving more metadata.
Yeah, we're unlikely to implement delegate constructor methods in native AOT. Doing so would require considering all address-taken methods to be visible from reflection (because this operation would fail without the metadata). We're already forced to do that for methods that are targets of delegates and that's not great either. Cc @Sergio0694
Could ILCompiler scan usages of delegate constructors and only keep the required metadata for methods that match the signature of a delegate created from an unidentified pointer? This way this wouldn't bring more metadata if such delegate creation isn't used.
It can, but it would be a very complicate analysis for a very niche scenario.
If you want to do things like convert delegates, reflection works as good as the proposed method without any additional analysis.
Background and motivation
In some cases a programmer might have a function pointer to a managed method while needing to have a delegate to it. One could then wrap such function pointer in a capturing delegate but that incurs both the cost of an additional indirection and looses reflection info for the method. Creating a delegate with a pointer is already possible in IL on CoreCLR, but IIRC NativeAOT doesn't fully implement the constructor for it. It'd be preferable however to have such possibility be exposed in C#.
Exposing this would make it possible to convert between delegate types since you could create a delegate of a new type with a pointer from the old delegate.
This would also help with the language not exposing a way to call instance function pointers today.
This API is unsafe since the runtime currently has no way to verify if a function pointer points to a valid managed method and crashes on such pointer (see #85197).
API Proposal
API Usage
Alternative Designs
Exposing the hidden pointer constructor on delegates, this however would not suggest that such operation is unsafe.
Risks
Users crashing the runtime by providing invalid function pointers.