Skip to content

[jnigen] Migrate callbacks to Dart_CObject_kNativePointer#3452

Open
liamappelbe wants to merge 11 commits into
mainfrom
jnigen_callbacks
Open

[jnigen] Migrate callbacks to Dart_CObject_kNativePointer#3452
liamappelbe wants to merge 11 commits into
mainfrom
jnigen_callbacks

Conversation

@liamappelbe

@liamappelbe liamappelbe commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

There are 2 buggy callback cases we're trying to fix:

  1. The target isolate is deleted before the callback message is sent
  2. The target isolate is deleted after the message is sent but before it's handled

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_DL sends from Dart_CObject_kInt64 to Dart_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_DL returns 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

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

PR Health

Breaking changes ✔️
Package Change Current Version New Version Needed Version Looking good?
jni Non-Breaking 1.0.0 1.0.1-wip 1.0.1-wip ✔️

This check can be disabled by tagging the PR with skip-breaking-check.

API leaks ⚠️

The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.

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.

@liamappelbe liamappelbe marked this pull request as ready for review July 6, 2026 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant