-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Expose an Unsafe.CallIndirect
method.
#23062
Comments
I would kind of prefer the C# compiler team adds dotnet/roslyn#11475 to their schedule instead. We have had to work around that in CoreRT for years. If someone isn't satisfied with the |
That is why I suggested "maybe having explicit <TDelegate, TArg, TResult>, <TDelegate, TArg1, TArg2, TResult> overloads would be better" in the other thoughts section.
I fully expect we will get proper The point of this proposal is to provide a stop-gap between now and C# 8 (or later, if it gets pushed out) and to provide a stop-gap mechanism for other languages missing such a feature. Providing generic overloads for the arguments ( |
I certainly wouldn't switch any of my
I get what you're saying, but there's not really such a thing as a "stop-gap" for the BCL. This would have to be supported forever, on all of our runtimes, even when the proper solutions (static delegates or compiler intrinsics) come into existence. Is there a way we can "bump up the priority" of the language features (either/or/both)? It feels to me that they would be very, very helpful at addressing a clear gap in the current system. |
dotnet/roslyn#11475 is not a language feature - it's just a matter of someone sitting down and doing it. I'll buy beers (or other beverage of their choosing) to the person who makes it happen because I really want to use it in CoreRT. The feature was discussed in LDM in January. I would hope we can find someone to do it in the 7.x timeframe. |
@MichalStrehovsky Good point, it's just a "compiler feature". I also really want to use it, and I've discussed it with a few other projects who would use it. |
I think there are always going to be languages that don't support this (possibly just because it is out of scope for the language). I also think, that while compiler intrinsics are nice, it is probably more worthwhile to invest in actual language features that expose things in desired ways (for the compiler team, what is the benefit of providing a I think the
Sadly, I don't think so. Like most of the teams, there is plenty of backlog for requested features, planned features, etc and only so many devs that can work on them. So it all comes down to priorit, need, etc |
Yet you're proposing a feature that puts it on the backlog of CoreCLR, CoreRT/.NET Native, and Mono teams :). System.Runtime.CompilerServices.Unsafe targets NetStandard 1.0 - requiring runtime features will require bumping it way up.
The proposed intrinsics have a broader applicability because they're not limited to static methods. Static delegates would only cover maybe a half of my use cases and I'm only half as excited about them. |
I'm slightly more confident in being able to implement one of those myself :) |
The right thing to do is for the C# Compiler to just implement the ability to emit I even have a working implementation I've been using for a year or so that we use internally at Bing. mjsabby/roslyn@e6123e0 (or as a nuget package like Microsoft.Net.Compilers package, https://www.nuget.org/packages/CSCWithCompilerIntrinsics) The only part I don't like about my implementation is that it generates the Prior to this I had my own tool like @mellinoe, https://github.com/mjsabby/PInvokeCompiler and I'm sure many others have reinvented their own. So I don't think the proposal here makes sense, but we should ping the Compiler Intrinsics proposal again. |
@tannergooding, can this be closed in favor of the function pointer support coming in C#? |
@tannergooding I have a need for this and thought perhaps you might detail how you would write the IL for this e.g. how would you implement the below in IL: public static TResult CallIndirect<TDelegate, TArg1, TArg2, TResult>(
IntPtr ptr, TArg1 arg1, TArg2 arg2); and what other alternatives are there to using I understand you might use UPDATE: The question of static vs instance methods also pops up. How is/could that be handled? |
I would likely wait for C# 9 and function pointers at this point. They will allow you to properly use There is a lot of complexity around |
I can't wait 😉
Right, that makes more sense to me then. Anyway, I really want to try to do this, since I have an immediate need, but also just as a learning exercise :) Would you mind if I ask some questions around this? I could give a concrete example for some specific types and take it from there. The idea was to add this to my own copy of |
I'm happy to answer questions but I don't believe you will be able to implement this as proposed in any form of library without JIT support.
The next best thing, if waiting for function pointers to get merged to master and be available in nightlies is too long, is likely using something like Fody to do IL rewriting to use |
Sounds like you expect this sooner than I would have thought? :) UPDATE: As an outsider viewing at the below two issues would indicate there is still some ways to go :) |
@tannergooding anyway, to ask a specific question, lets look at the following type (just an example): public class ComparableClassInt32
: IComparable<ComparableClassInt32>
{
public readonly int Value;
public ComparableClassInt32(int value) =>
Value = value;
public int CompareTo(ComparableClassInt32 other) =>
Value.CompareTo(other.Value);
} Now I would like to call
That is That is in my case, this is just for calling managed code, not interop. Hence, calling conventions is not an issue I guess. |
Rationale
Today, in C#, you can only invoke an unmanaged function pointer by first calling
Marshal.GetDelegateForFunctionPointer
and then invoking the resulting delegate that is created.This not only comes with the increased overhead of the call (
Marshal.GetDelegateForFunctionPointer
) itself, but it also incurs a heap allocation and a 4-6x memory increase, not including internal runtime allocations/overhead -- theMulticastDelegate
type has anobject
and anIntPtr
field and the baseDelegate
type itself has twoobject
and twoIntPtr
fields -- Invoking the method also has some increased overhead as it goes through theDelegate.Invoke
call rather than as a direct invocation.The C# language has planned support for
static delegates
in the future (https://github.com/dotnet/csharplang/blob/c5de26f52019ca0e1e79d88584f75bfe530ee986/proposals/static-delegates.md), but those may still be a way off and could potentially not come at all.Other languages may also face similar issues if they do not provide equivalent support.
Proposal
We should expose a new method on the
System.Runtime.CompilerServices.Unsafe
type that functions as an equivalent to thecalli
instruction.The runtime should treat this as an equivalent to the
calli
instruction with a signature matchingTDelegate
.The runtime should validate that
TResult
/args
matches the return/input type ofTDelegate
.Other Thoughts
Using generics means that pointers are harder to use, there would have to be support to interpret
IntPtr
andUIntPtr
args (those passed toCallIndirect
) as equivalent to a pointer (as declared for the corresponding field inTDelegate
).The current proposal (using
params object[]
) means boxing for arguments, maybe having explicit<TDelegate, TArg, TResult>
,<TDelegate, TArg1, TArg2, TResult>
overloads would be better?I think, for either case,
out
andref
would not be readily supported unlessUnsafe.AsRef
were used internally (also having special handling to interpretIntPtr
andUIntPtr
asref
equivalents).Example Usage
A user might have a manually authored interop type such as:
In order to invoke
EnumAdapters
today, the user would code something similar to:Under the proposal, someone would now declare:
The text was updated successfully, but these errors were encountered: