-
Notifications
You must be signed in to change notification settings - Fork 63
Change JniNativeMethodRegistration.Marshal to IntPtr #1364
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
Change JniNativeMethodRegistration.Marshal to IntPtr #1364
Conversation
| Java.Interop.JniTypeSignatureAttribute.InvokerType.set -> void | ||
| Java.Interop.IJavaPeerable.JniObjectReferenceControlBlock.get -> nint | ||
| Java.Interop.JniNativeMethodRegistration.JniNativeMethodRegistration(string! name, string! signature, nint marshaler) -> void | ||
| *REMOVED*Java.Interop.JniNativeMethodRegistration.Marshaler -> System.Delegate! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To reduce the API break, can we leave the old member there and put [Obsolete] on it? We could also continue setting the value, just in case?
Then the new member is MarshalerPtr?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added added a Member property getter as you suggested so this is not a source breaking change but only an ABI breaking change.
|
I do not understand the need for this change. dotnet/android#10472 is an exception from the use of The other question raised in dotnet/android#10472, but not explicitly asked or answered, is where does the generic delegate come from? The answer to that unasked question is "from Mono.Android.Export.dll", e.g. Plus lots of other changes. Aside: I like the idea, but this is without question both an API and an ABI break, because JniNativeMethodRegistration CreateRegistration()
{
JniNativeMethodRegistration s;
s.Name = "a";
s.Signature = "()V";
s.Marshaler = null;
return s;
}Turning the field (Is there any such code in the wild? Probably not. Thus, this might be fine. Maybe.) |
|
@jonpryor thanks for the feedback, I update the PR description to better state the motivation for this change and hopefully clarifies the points you raised.
I added a setter to the
As I wrote in the updated PR description, this is an API change, but I believe it is justified. An alternative would be introducing a new struct |
|
Closing this PR because a revisited solution dotnet/android#10503 does not require these changes. |
…#10503) The problem is that the Marshal.GetFunctionPointerForDelegate method does not work with delegates with generic types, such as `Action<...>` or `Func<...>` (context: dotnet/runtime#32963), which was the case of all the delegates created in `Mono.Android.Export` through `DynamicMethod`. This PR replaces the use of these generic delegate types with dynamically built non-generic types. It is based on an existing implementation in java-interop (see [here][0]). The CoreCLR is able to marshal the delegates built with these types to function pointers just fine. In a previous attempt at fixing this issue (#10493), I chose a solution which modified the shape of `JniNativeMethodRegistration` which would be an ABI breaking change (dotnet/java-interop#1364). This implementation is much simpler and doesn't cause the same problem. Thanks to @jonpryor for steering me in this direction. [0]: https://github.com/dotnet/java-interop/blob/02bceb03f7c07858590d930ef507745a88200a48/src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.cs#L274-L311
That solves the API break, but leaves the ABI break. Any existing assemblies which use the (no longer existing!) It might be justified, but it could break existing code. (This could be addressed via an IL rewriter step! But such a thing would also need to be written.) I agree that making the However, what's done is done. There are only four paths forward:
Right now, (1) "do nothing" is the path forward, as this change isn't necessary to address dotnet/android#10472. (I can foresee a future where the |
Contributes to dotnet/android#10472
This change is necessary for a workaround for CoreCLR to allow us to register dynamically generated .NET methods as Java natives. The problem is that the
Marshal.GetFunctionPointerForDelegatemethod does not work with delegates with generic types, such asAction<...>orFunc<...>(context: dotnet/runtime#32963), which is the case of all the delegates created inMono.Android.ExportthroughDynamicMethod.It is possible to change the Mono.Android.Export implementation to use
TypeBuilderandMethodBuilderinstead of theDynamicMethodto define a new static method and obtain a function pointer to this method (see dotnet/android#10493). As a consequence of this change, it would be necessary to store theIntPtras theMarshalvalue directly instead of theDelegateobject (which is marshalled to an IntPtr when theJniNativeMethodRegistrationinstance is passed as an argument to a p/invoke).This is an ABI breaking change but I believe it is justified. To reduce the API breaking change, we can keep the
Delegate Marshaler { get; set; }property which will attempt to useMarshal.GetFunctionPointerForDelegateto convert the delegate to theIntPtrand also keep the original constructor which accepts the delegate as an argument.