fix(runtime): #4876 keep js_promise_report_unhandled_rejections alive through auto-optimize LTO#4883
Merged
Merged
Conversation
… through auto-optimize LTO Codegen emits an unconditional call to js_promise_report_unhandled_rejections in the generated _main (the program-end unhandled-rejection hook from the #4838/#4852 work), but the runtime symbol was being dropped by the auto-optimize whole-program-bitcode internalize+dead-strip pass. The fn is #[no_mangle] pub extern "C" and reachable only from generated .o, so without a #[used] anchor LTO internalized and stripped it — every native link (aarch64-apple-{darwin,ios,tvos}, x86_64-unknown-linux-gnu) failed with 'undefined symbol: js_promise_report_unhandled_rejections'. Android linked because it doesn't go through the same auto-optimize bitcode path. Fix: add a #[used] KEEP anchor in promise/then.rs, matching the existing keepalive pattern in error.rs and promise/combinators.rs.
proggeramlug
added a commit
that referenced
this pull request
Jun 11, 2026
) The auto-optimize runtime/stdlib rebuild caches its output in a `target/perry-auto-{hash}` dir keyed only on (features, panic_mode, target, wasm-host) — not on the compiler version. The object cache is already version-invalidated (build_cache.rs misses on `perry_version != CARGO_PKG_VERSION`), so the two caches disagree across a compiler upgrade on a persistent build host: - object cache rebuilds program objects with the new codegen, which emits calls to newly-added runtime entrypoints; while - the version-blind perry-auto dir hands back a stale `libperry_runtime.a` from the previous compiler that predates those symbols. Result: the final link fails with "undefined symbol" for exactly the entrypoints added since the cached runtime was built (and only those — older entrypoints resolve fine), e.g. `js_promise_run_promise_jobs`, `js_register_closure_strict_function`, `js_iterator_result_validate`, `js_promise_report_unhandled_rejections`, `js_mark_entry_module_esm`. This is why #4883's per-symbol `#[used]` anchor didn't help: the symbol isn't being stripped from a fresh build, it's absent from a stale cached one. Add `CARGO_PKG_VERSION` to the cache key so a compiler upgrade forces a matching runtime rebuild, mirroring the object cache. Co-authored-by: Ralph Küpper <ralph@skelpo.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4876.
Problem
Starting with v0.5.1151, every native link fails with:
Codegen emits an unconditional call to
js_promise_report_unhandled_rejectionsin the generated_main(the program-end unhandled-rejection hook added by the #4838/#4852 readable-unhandled-rejection work). The runtime defines the symbol (#[no_mangle] pub extern "C"inpromise/then.rs), but the auto-optimize whole-program-bitcode internalize + dead-strip pass drops it: the function is reachable only from generated.o, and without a#[used]anchor LTO internalizes then strips it.Affected:
aarch64-apple-{darwin,ios,tvos},x86_64-unknown-linux-gnu. Android linked because it doesn't go through the same auto-optimize bitcode path.Fix
Add a
#[used] static KEEP_PROMISE_REPORT_UNHANDLED_REJECTIONSanchor incrates/perry-runtime/src/promise/then.rs, matching the established keepalive pattern for codegen-only FFIs inerror.rsandpromise/combinators.rs.Validation
Built perry + runtime/stdlib, cleared
.perry-cache, compiled a minimal program with an unhandledPromise.reject. The auto-optimize path (rebuilds runtime+stdlib with LTO) now links cleanly:Before this fix the same compile failed at link with the undefined symbol.