Skip to content

fix(gc): three more re-read-vs-stale-local orderings around the async result promise (#7497 follow-up) - #7529

Merged
proggeramlug merged 3 commits into
mainfrom
fix/7497-followup-async-result-rooting
Aug 6, 2026
Merged

fix(gc): three more re-read-vs-stale-local orderings around the async result promise (#7497 follow-up)#7529
proggeramlug merged 3 commits into
mainfrom
fix/7497-followup-async-result-rooting

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #7516 (which landed as 5edfe99 while this was in flight). Same
family, three more re-read vs stale local orderings around the async result
promise, plus one honesty correction to #7516's changelog fragment.

The three orderings

  1. js_async_step_done passed the pre-root copy. fix(gc): Promise.all at scale read globalThis and its own combinator state from retired from-space (#7497) #7516 rooted trap_next
    and then handed resolve_trap_next_with_adoption the original binding
    anyway. Rooting is not a licence to keep using the old name — that is the
    exact shape fix(gc): Promise.all at scale read globalThis and its own combinator state from retired from-space (#7497) #7516 exists to remove.

  2. resolve_trap_next_with_adoption held its receiver across
    js_assimilate_thenable.
    That call runs a user then getter, and
    target is the receiver of both settlements after it. This is the one with a
    real user-facing path behind it (return <thenable> from an async fn —
    Drizzle's QueryPromise, await thenable returns the thenable itself instead of calling .then(resolve, reject) #586).

  3. The AsyncStep arm seeded INLINE_TRAP from its locals. Between the
    re-read at the top of the arm and the INLINE_TRAP.set sit the
    runaway-reentry guard (which allocates a TypeError on its bounded path) and
    two handle pushes. A stale next parked in the trap is what
    js_async_step_done later settles and returns as the async function's own
    result promise.

What this does NOT do, stated plainly

#7516's fragment recorded one open residual: a protected run
(PERRY_GC_PROTECT_FROMSPACE=1) of the auto-optimize binary prints the correct
checksum and then faults inside js_async_step_done. All three changes above
were attempts at it and none of them cleared it
— the holder is somewhere I
have not found. The fragment is amended to say so rather than leaving the
impression that the instrument is clean or that one more re-read would do it.

Each change is nonetheless correct on its own terms and is kept for that reason,
not because it was measured to fix something.

Verification (before the merge of #7516 moved main under it; re-checked after

the rebase)

  • benchmarks/app-patterns/kernels/promise_all_chains.tschecksum: 2500050000,
    byte-exact vs node 26.5.1, on both link modes.
  • scripts/auto_opt_app_patterns.sh — 12/12, no skips.
  • test_gap_gc_global_builtin_lookup_rooting.ts plus 8 promise/array/async gap
    tests — all byte-exact.
  • cargo test -p perry-runtime — 1744 passed, 0 failed.
  • scripts/raw_handle_debt.py 999 (unchanged), cargo fmt --check clean.

Summary by CodeRabbit

  • Bug Fixes

    • Improved async promise handling during garbage collection and thenable adoption.
    • Strengthened preservation of async task state across promise resolution and runtime transitions.
    • Updated async execution safeguards to use current values after memory-management operations.
    • The remaining auto-optimization crash is still under investigation and was not resolved by these changes.
  • Documentation

    • Added changelog details covering the attempted fixes, verification results, and known limitations.
  • Maintenance

    • Updated the release version to 0.5.1299.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d385e248-d58a-4e15-8495-16c9d4c6740d

📥 Commits

Reviewing files that changed from the base of the PR and between 5eda89a and 9ad65a0.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • CLAUDE.md
  • Cargo.toml
  • changelog.d/7516-promise-all-chains.md
  • changelog.d/7529-async-result-rooting.md
  • crates/perry-runtime/src/promise/async_step.rs
  • crates/perry-runtime/src/promise/microtasks.rs

📝 Walkthrough

Walkthrough

The runtime re-reads rooted promise, value, and closure pointers after allocation-sensitive operations. Changelog entries document the attempted fixes and verification results. The protected auto-optimized crash remains unresolved.

Changes

Async Promise GC Pointer Stabilization

Layer / File(s) Summary
Promise rooting and re-read handling
crates/perry-runtime/src/promise/async_step.rs, changelog.d/7529-async-result-rooting.md, changelog.d/7516-promise-all-chains.md
js_async_step_done returns the re-read rooted promise. Thenable assimilation re-reads the rooted target and value. Changelogs record the fixes and verification results.
Async-step trap pointer reload and version update
crates/perry-runtime/src/promise/microtasks.rs, Cargo.toml, CLAUDE.md
Task::AsyncStep reloads next and step_closure before setting INLINE_TRAP. The workspace and documented versions change to 0.5.1299.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: bug

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the async result promise fixes and their re-read-versus-stale-local focus.
Description check ✅ Passed The description explains the changes, residual fault, related issue, and verification results, although it does not use every template heading.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/7497-followup-async-result-rooting

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

proggeramlug pushed a commit that referenced this pull request Aug 6, 2026
Ralph Küpper added 3 commits August 6, 2026 15:32
… result promise (#7497)

js_async_step_done passed the pre-root copy of trap_next to the settle instead
of the re-read address; resolve_trap_next_with_adoption held its receiver across
js_assimilate_thenable, which runs a user then getter; and the AsyncStep arm
seeded INLINE_TRAP from its locals rather than from the handles it had just
re-read.

All three are correct on their own terms and none of them clears the residual
post-output fault in js_async_step_done under the auto-optimize link, which the
changelog now says explicitly rather than implying the instrument is clean.
@proggeramlug
proggeramlug force-pushed the fix/7497-followup-async-result-rooting branch from 2c6c15a to 9ad65a0 Compare August 6, 2026 13:32
@proggeramlug
proggeramlug merged commit 3195e61 into main Aug 6, 2026
7 of 12 checks passed
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

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