Description
Background and Motivation
Native varargs are a complicated interop scenario to support. At present, native varargs are only supported on the Windows platform through the undocumented __arglist
keyword. Supporting varargs naturally in a P/Invoke scenario would be difficult from the C# language. However, it is possible to compromise by permitting support for the call with a fully specified DllImport
signature and a hint from the user.
User scenario: #48752
Proposed API
namespace System.Runtime.InteropServices
{
+ [AttributeUsage(AttributeTargets.Method)]
+ public class NativeVarargsAttribute : Attribute
+ {
+ public NativeVarargsAttribute() { VarargBeginIndex = 0; }
+
+ /// <summary>
+ /// Zero-based index of the first variable argument.
+ /// </summary>
+ public int VarargBeginIndex;
+ }
}
Usage Examples
Consider the following native export with varargs:
void Varargs(int n, ...);
The following P/Invoke declarations would enable users to call and properly forward the arguments in a supported multi-platform manner.
[NativeVarargsAttribute(VarargBeginIndex = 1)]
[DllImport(@"NativeLibrary.dll", EntryPoint = "Varargs")]
static extern void Varargs0(int n);
[NativeVarargsAttribute(VarargBeginIndex = 1)]
[DllImport(@"NativeLibrary.dll", EntryPoint = "Varargs")]
static extern void Varargs1(int n, int a);
[NativeVarargsAttribute(VarargBeginIndex = 1)]
[DllImport(@"NativeLibrary.dll", EntryPoint = "Varargs")]
static extern void Varargs2(int n, int a, int b);
Alternative designs
Encode the information in the CallingConvention
enum. This approach does remove the overhead of attribute reading, but does miss the added data of knowing where the varargs start - at present doesn't appear to be needed. This approach also impacts existing metadata tooling (for example, ILDasm, ILAsm, and ILSpy). See #48796 (comment).
public enum CallingConvention
{
+ VarArg = 6
}
Current state
Without this feature, calling functions with native varargs isn't possible on a non-Windows platforms. The proposed workaround is to create native shim libraries and instead P/Invoke into them. Continuing the example above, the shim library would export the following:
extern void Varargs(int n, ...);
void Varargs0(int n)
{
Varargs(n);
}
void Varargs1(int n, int a)
{
Varargs(n, a);
}
void Varargs2(int n, int a, int b)
{
Varargs(n, a, b);
}
References
Support on Windows: dotnet/coreclr#18373
JIT details: #10478
Metadata
Metadata
Assignees
Type
Projects
Status