Cesium
Cesium copied to clipboard
`FuncPtr` interop: support more than 16 arguments
In #354, we've introduced FuncPtr
interop: C code may call .NET Core and pass function pointers in the positions when FuncPtr<TDelegate>
is expected.
Currently, we are limited to 16 parameters for each such function because there are no longer delegate types in .NET runtime.
We should support functions of any length instead, perhaps by inventing a custom calling convention on ValueTuple
s.
While implementing it, seek for number 493
in the code.
Why not use function pointer (delegate* managed <Arg1, Arg2, Arg3, etc, RetType>) instead of System.Delegate? delegate* <> is a void*. You can get the pointer via ldftn <MethodReference>. And you can call the pointer via calli <Callsite>. Callsite is a signature like <Arg1, Arg2, etc, RetType> + AdditionalFlags (like cdecl/stdcall or managed callin convention). If non-Managed callconv is selected, dotnet adds anti-exception barriers, but it is slightly slower. You can also call native methods in this way. For callback things and all that. The maximum number of arguments is many times more than 16. Since delegate*<> is an intptr, there is no runtime checking of arguments. I.e. you can call Foo(int, int) as Foo(int) or Foo(int,int,int). Hence a funny error. If you call Foo(float) as Foo(int), the latter will not get float because float is passed through Xmm1 registers and int is passed through RCX (on x64, if I remember correctly.
I will split your question into several parts.
- Why not use (function) pointers directly? Because they don't have a constant size, and for the Wide architecture, we need a portable pointer of exactly 8 bytes. Feel free to skim over the corresponding documentation.
-
Why not use a function pointer as an argument for
FuncPtr
? Because that's impossible. Pointer types can't be used as generic arguments. -
Do we have to use all that stuff at all? No, we do not have. If compiling against native architectures[^1], Cesium doesn't emit
CPtr
/VoidPtr
/FuncPtr
interop, and uses the function pointers directly.
[^1]: Everything except Wide.