Skip to content

Support C# Function Pointers? #666

Open
@jonpryor

Description

@jonpryor

Context: https://github.com/dotnet/csharplang/blob/master/proposals/function-pointers.md
Context: dotnet/runtime#32963

There is a proposal to add function pointers to the C# language. This would allow obtaining a pointer to a C# static method and hand it to native code without going through Delegates, and would be more efficient.

By @jonpryor's reading of the spec, In order to create a function pointer which can be handed off to native code, the method needs to have a [NativeCallableAttribute] declaration, but:

Methods marked by [[NativeCallable]] attribute are only callable from native code, not managed (can’t call methods, create a delegate, etc …).

This restriction means that we can't use the existing JNINativeWrapper.CreateDelegate() approach, which is used as part of exception marshaling, e.g.

https://github.com/xamarin/java.interop/blob/ef1d37b00ca7f84f9d07e057857af938816205a3/tests/generator-Tests/Tests-Core/expected.ji/Android.Text.ISpannable.cs#L70

The "easiest" way to support C# function pointers, if/when they ever exist, will be to integrate support into jnimarshalmethod-gen, such that instead of emitting

partial class __<$>_jni_marshal_methods {
    public static IntPtr FuncIJavaObject (IntPtr __jnienv, IntPtr __this) {}

    public static void __RegisterNativeMembers (JniNativeMethodRegistrationArguments args)
    {
        args.AddRegistrations (new JniNativeMethodRegistration[]{
                new JniNativeMethodRegistration ("funcIJavaObject",
                    "()Ljava/lang/Object;",
                    new Func<IntPtr, IntPtr, IntPtr> (FuncIJavaObject)),});
    }
}

We would emit "equivalent" code which uses [NativeCallable] and function pointers:

partial class __<$>_jni_marshal_methods {
    [NativeCallable]
    public static IntPtr FuncIJavaObject (IntPtr __jnienv, IntPtr __this) {}

    public static void __RegisterNativeMembers (JniNativeMethodRegistrationArguments args)
    {
        delegate*<IntPtr, IntPtr> fp = &FuncIJavaObject;
        args.AddRegistrations (new JniNativeMethodRegistration[]{
                new JniNativeMethodRegistration ("funcIJavaObject",
                    "()Ljava/lang/Object;",
                    (IntPtr) fp),});
    }
}

Note that for the above to work, we'd need to add a JniNativeMethodRegistration(string, string, IntPtr) constructor, which may be difficult to do without an ABI break, as that type only exposes fields, not properties, and we can't change the size of that struct:

https://github.com/xamarin/java.interop/blob/master/src/Java.Interop/Java.Interop/JniNativeMethodRegistration.cs

I doubt anybody is currently using this struct, so it might not be a problem to break ABI, but if it is, we'll need to think of a workaround.

Metadata

Metadata

Assignees

No one assigned

    Labels

    proposalIssue raised for discussion, we do not even know if the change would be desirable yet

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions