[jnigen] Migrate callbacks to Dart_CObject_kNativePointer#3452
Conversation
PR HealthBreaking changes ✔️
This check can be disabled by tagging the PR with
API leaks
|
| Package | Leaked API symbol | Leaking sources |
|---|---|---|
| jni | $JCollection | core_bindings.dart::JCollection::implementIn::$impl core_bindings.dart::JCollection::implement::$impl |
| jni | $JIterator | core_bindings.dart::JIterator::implementIn::$impl core_bindings.dart::JIterator::implement::$impl |
| jni | $JList | core_bindings.dart::JList::implementIn::$impl core_bindings.dart::JList::implement::$impl |
| jni | $JMap$JEntry | core_bindings.dart::JMap$JEntry::implementIn::$impl core_bindings.dart::JMap$JEntry::implement::$impl |
| jni | $JMap | core_bindings.dart::JMap::implementIn::$impl core_bindings.dart::JMap::implement::$impl |
| jni | $JSet | core_bindings.dart::JSet::implementIn::$impl core_bindings.dart::JSet::implement::$impl |
This check can be disabled by tagging the PR with skip-leaking-check.
Changelog Entry ✔️
| Package | Changed Files |
|---|
Changes to files need to be accounted for in their respective changelogs.
This check can be disabled by tagging the PR with skip-changelog-check.
dcharkes
left a comment
There was a problem hiding this comment.
LGTM!
Looking forward to having users be able to do custom cleanup callbacks.
| jni$_.Pointer<jni$_.Void>, jni$_.JMethodIDPtr, core$_.int)>(); | ||
|
|
||
| /// from: `static public boolean isJavaLetter(char c)` | ||
| @core$_.Deprecated('This Java method is deprecated.') |
There was a problem hiding this comment.
This is unrelated to this PR?
There was a problem hiding this comment.
A recent external PR added @Deprecated annotations, but it seems they didn't regen all the bindings. Not sure why this didn't show up on CI.
There are 2 buggy callback cases we're trying to fix:
In both cases, the arguments being sent are leaked. For blocking callbacks, both cases also block the Java thread forever waiting for the response. 50331f3 contains tests for this buggy behavior.
To fix case 1 we just have to check the return value of
Dart_PostCObject_DL. If it returns false we clean up the args and mark the blocking callback result as ready.To fix case 2 we have to migrate the message
Dart_PostCObject_DLsends fromDart_CObject_kInt64toDart_CObject_kNativePointer. This allows us to attach a finalizer that will be called if the message sends ok, but the target isolate shuts down before the message is handled. I've verified that the finalizer is not called if the message fails to send (Dart_PostCObject_DLreturns false), or if the message is sent and handled successfully.The full design of this solution also involved allowing the developer to include a custom cleanup function. We're not tackling that in this PR. We'll do that later.
There was a similar bug in
PortContinuation, so I also applied the fix there.Also, JNI bundles the callback args into a Java array. Before this PR the Dart wrapper around that array was allowed to go out of scope after the callback, eventually to be GC'd. Instead we now eagerly release it. Note that this doesn't release the args themselves, just the wrapper array ref. This makes the tests more deterministic. Alternatively we could have triggered a Dart GC during the test, but eagerly releasing the array is better for performance.
Part of #3265