Skip to content

fix(darwin): release runtime registrations and native temporaries - #12

Open
kfdykme wants to merge 1 commit into
predatorx7:mainfrom
kfdykme:codex/fix-darwin-runtime-lifecycle
Open

kfdykme wants to merge 1 commit into
predatorx7:mainfrom
kfdykme:codex/fix-darwin-runtime-lifecycle

Conversation

@kfdykme

@kfdykme kfdykme commented Sep 15, 2026

Copy link
Copy Markdown

Description

Fix lifecycle retention and temporary native allocations in javascript_darwin.

Problems

  • JavascriptRuntime.channelFunctionsRegistered is a static map. Disposing a
    JavascriptCoreRuntime releases its native context but leaves its channel map
    behind. The SetTimeout callback closes over the runtime, retaining it (and
    application callbacks) after disposal. The context-to-engine-ID map also keeps
    stale entries.
  • Dart Future replies and Promise polling can attempt to evaluate JavaScript
    after the context has been released. A pending timeout also retains its closure
    until it fires, even though it checks isDisposed before evaluating.
  • Evaluation, property access and JSON conversion create native string references
    and pointer output slots that are not consistently released.

Changes

  • Make disposal idempotent; remove per-engine registries before releasing JSC,
    cancel tracked timeouts, and clear runtime-owned Dart context maps.
  • Reject direct evaluation/conversion on a disposed runtime; skip late channel
    replies and stop Promise polling with a Dart error on disposal.
  • Balance Create/Copy-owned strings and temporary pointer slots in the affected
    runtime paths. Use nullptr for ignored optional exception outputs instead of
    allocating an unused slot. Borrowed JSValueRefs are not freed or finalized.
  • Guard null JSON string references (e.g. undefined, functions, symbols and
    cycles); return the JSON null fallback without releasing a null pointer.
  • Catch callback/JSON decoding errors inside the existing channel handling try
    block and JSON-escape asynchronous error strings.

Reproduction / validation

On macOS, from packages/javascript_darwin:

flutter test

All 7 tests pass with Flutter 3.41.9. The new tests use real JavaScriptCore
contexts and cover 100 repeated context lifecycles, registry cleanup, double
disposal, isolation between runtimes, late successful/failed replies, pending
Promise polling, live async JSON replies and non-serializable JSON inputs.
Native runtime tests are skipped on non-macOS hosts.

A downstream iOS host was also tested in profile and Debug for 30 create/use/
dispose cycles with these fixes: post-GC runtime instances went from 30 retained
instances to 0. This is supporting lifecycle evidence, not a claim that all
native contexts were previously leaked or all RSS growth is now eliminated.
No downstream application code or internal device logs are included here.

Targeted analysis of the runtime and new test has no errors or warnings; eight
existing style-level infos remain. This PR does not claim repository-wide clean
analysis or overhaul every vendored low-level JSC wrapper.

Scope / compatibility

No package version bump or dependency override. Android is untouched.
Direct use after dispose now throws StateError instead of entering a released
context. Unserializable JSON values use the null fallback. Vendored source is
patched in place, as with the package's existing adapter changes.

Type of Change

  • New feature
  • Bug fix
  • Breaking change
  • Code refactor
  • Build configuration change
  • Documentation
  • Chore
  • Test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant