-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Source generation of ILStub for DllImport #43060
Comments
Would it make sense to add "Enable evolution of PInvoke marshalling" to the list of goals? If yes, it would be nice to have "Add one high-value marshaller that does not exist today" in the exit criteria list. My pick would be marshaller for |
Doh! That was the section I couldn't think of but knew I was missing something - innovation. Yes, that should be added. |
Interesting! Thanks for the nice example in the design doc. To make sure I followed completely - the runtime will still generate a P/Invoke wrapper, it's just that we're guaranteed to only see blittable types? @marek-safar this dovetails nicely with the discussion we had about partitioning From the FAQ:
😞 so we can only get rid of half of |
Right. Presently there is a level of indirection between the managed invocation and the native call - typically called an IL Stub. The IL Stub marshals the input types to appropriate blittable types and then makes the native call via In the proposed model the IL Stub is generated at compile time and a P/Invoke with all blittable types is created. We are relying on the JIT's optimization of inlining P/Invoke calls with all blittable types. This inlining optimization is typically only available on Release builds. There are several nice things about this approach, but one of the ones I accidentally discovered was that this model permits inlining in more cases. The following signature
Nice to hear. CoreCLR has no plans on changing any aspect of the built-in system in response to this work. This model is interesting and being explored primarily for AOT and innovation possibilities.
Generating a Reverse P/Invoke stub is possible using this methodology in some scenarios - consider callbacks being passed to native - one could imagine a solution there. The other type of Reverse P/Invoke would be the native export of a manage function - this is probably the one being alluded to here. Utilizing the code generation approach it should be possible to extend the |
We should discourage use of delegates for reverse P/Invoke and encourage use of function pointer instead Maybe the analyzer that comes with this should be emitting warnings for delegate marshaling? |
@jkoritzinsky We should consider this after we ensure we have symmetry with the current system. Perhaps we could defer creating a Delegate marshaller entirely for now? |
Nice to see this moving forward! A few questions
@lambdageek I think on platforms we need to cut the size we can rely on the analyzer to block reverse P/Invoke. |
I've done this with the Silk.NET Marshalling system, see SilkTouch could be of use if this is eventually implemented (we don't use P/Invoke under the hood, on .net core 3.0+ we instead use |
That is mentioned in the exit criteria as something we need to track.
This should have no impact on that as defined. If this changes to
Yes. This is intended as a drop in replacement for |
Great feedback on source generators - @chsienki any thoughts here?
All generated code is going to be valid C#. The only issue with previous tooling solutions not being able to have pure C# was |
I think, somewhat touching on what @HurricanKai was discussing, there are scenarios where you can't use Does this also cover generating wrappers for function pointers? Would it alternatively be possible to allow hooking into export resolution much as we all hooking into library resolution via NativeLibrary.SetDllImportResolver? |
This sounds like having the ability to create an IL Stub that can be used outside of
This will continue to work with this current model. We are using the existing model of export discovery so all these callbacks will continue to be respected. |
+1 on Tanner's comment - At Silk.NET we have to maintain and swap out different native function tables for each Vulkan instance and device. OpenXR has similar restrictions, not to mention OpenGL's platform-specific loading strategies. NativeLibrary has helped with this in that we can control what function pointers P/Invoke is fed and we use NativeLibrary where available, but until .NET 6 Silk.NET is restricted to .NET Standard because of mobile support, so we have to manually load in using libdl or kernel32 on non-.NET Core platforms. Today's challenges is P/Invoke simply doesn't offer the level of freedom advanced scenarios such as these require, where the underlying native function addresses are context-dependent (this is why Silk.NET exposes its native functions through instances instead of static functions) and need to be directly accessed in some cases (a la function pointers) Massively thankful to Kai for championing SilkTouch and thankful to the C# LDM and Roslyn teams for making SilkTouch possible - our solution before this was a much slower System.Reflection.Emit-based approach (called SuperInvoke) in order to wield calli and do the marshalling we needed. |
I was asking if it would be possible to expose a hook for resolving a [DllImport("vulkan", ExactSpelling = true)]
public static extern VkResult vkCreateDebugReportCallbackEXT(IntPtr instance, VkDebugReportCallbackCreateInfoEXT* pCreateInfo, VkAllocationCallbacks* pAllocator, ulong* pCallback); Where This would, for example, allow the general |
You can do it using function pointers today. It is a niche case - it was discussed before. I do not think it is worth the complexity. |
Fair enough, that just relegates it to potentially future source generator support around function pointers. |
Yes. That is one of the reasons we will be ensuring a final marshalling code library is |
Since a very large portion of P/Invokes in Microsoft.NETCore.App use delegate callbacks and we've already added the support for Delegate marshalling, I suggest we keep it, at least for v1 where we're trying to do a drop-in replacement for DllImport. I wouldn't be against emitting a warning, although I think we should hold off on that until we have some sort of reverse P/Invoke generation. |
FWIW, the number of P/Invokes in Microsoft.NETCore.App that use delegate callbacks is relatively small, and I plan to convert majority of them to use function pointers now that we have the Roslyn with the final syntax. |
Will this cover the ownership transfer for SafeHandles // Release on failure
using (safeHandle)
{
if (nativeCall(safeHandle))
{
// The handle ownership has been transferred; don't release.
safeHandle.SetHandleAsInvalid();
}
} As used in Lines 67 to 76 in 1d9e50c
Lines 471 to 476 in 1d9e50c
runtime/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs Lines 200 to 206 in f93c0e6
Lines 1153 to 1162 in 1d9e50c
Lines 202 to 211 in f9a8abc
etc |
@benaadams I've taken another look and I believe that a marshaler that handles that case (SafeHandle either transferred ownership or released) would be possible for a developer to write with the source generator's custom marshalling model. |
Based on this comment:
This would mean that code like this, would be able to be simplified to what look like managed types on the surface, and the marshalling and forced conversion/check for blittability (is this a word? blittableness? 😅) would happen under the hood? https://gist.github.com/GavinRay97/b3e92ca3245319eb358e4a882ab5c942 Though this would be more of a |
The Roslyn source generator feature has created an opportunity for the Interop team to consider the generation of the P/Invoke ILStub at compile time instead of during run time. A proposal for this work can be found here.
Prototyping is occurring in the
dotnet/runtimelab
.Goals
NetCoreApp
.NetCoreApp
.ReadOnlySpan<T>
/Span<T>
).Non-Goals
NetCoreApp
.Prototype exit criteria
NetCoreApp
in a local build.NetCoreApp
can be updated with confidence.Span<T>
). Implement marshallers for Span and ReadOnlySpan runtimelab#1222designs/
folder in repository.NetCoreApp
NetCoreApp
. See Disable EventSource generator in design-time builds #50741 for concern.NetCoreApp
using the source generator prototype with stakeholders.Source generator prototype
All work is current taking place in
dotnet/runtimelab
.NetCoreApp
- Get P/Invoke information from assembly metadata runtimelab#146bool
Delegate
SafeHandle
- SafeHandle marshalling runtimelab#133char
- Add Char marshaller runtimelab#212string
- String marshallers for UTF-16 and UTF-8 runtimelab#249, Add string marshallers for ANSI and platform-defined runtimelab#288Array
[Out] Foo[]
) - Add handling for [In, Out] attributes. runtimelab#380Span<T>
orReadOnlySpan<T>
) - Implement marshallers for Span and ReadOnlySpan runtimelab#1222DllImportAttribute
options (support, pass-through, or error).PreserveSig
- Handle PreserveSig=false runtimelab#323BestFitMapping
,ThrowOnUnmappableChar
, andLCIDConversion
- Report diagnostic forBestFitMapping
,ThrowOnUnmappableChar
, andLCIDConversion
runtimelab#291SetLastError
- Handle SetLastError=true runtimelab#360ExactSpelling
,EntryPoint
,CharSet
,CallingConvention
- Pass through to blittableDllImport
P/Invoke.SkipLocalInitAttribute
to stubs - Apply SkipLocalsInitAttribute to generated stubs. runtimelab#377// <auto-generated/>
comment. - Comment in source that source file is auto-generated. runtimelab#1209F5
to treat test like an "exe". -Demo
projectDNNE
to avoid native build system support.BenchmarkDotNet
.EventSource
events for indicating DllImport source generator begin/end. - Add event for marking the Start/Stop of source generation runtimelab#258MarshalEx
=>Marshal
. - Implement support for configurable generator options. runtimelab#458#define
. - Implement support for configurable generator options. runtimelab#458DllImport
<=>GeneratedDllImport
.New .NET APIs
New APIs that will need to be introduced - remember to consider Linker semantics:
SetLastError()
). Expose setting/getting of system error code #46843.SafeHandle
s. Expose interop manipulation of SafeHandle #46830.GeneratedDllImport
attribute and analyzer. LibraryImportAttribute for p/invoke source generation #46822.CallingConvention
enumeration. Extensible Calling Conventions for native callee functions #51156.All above APIs have inefficient but semantically correct implementations in the
Ancillary.Interop
project.Once prototyping has completed the above APIs will go through an official API review in
dotnet/runtime
.The text was updated successfully, but these errors were encountered: