Skip to content

ZJIT: Fix SP alignment on JIT-to-JIT calls for x86_64 #13900

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 16, 2025

Conversation

k0kubun
Copy link
Member

@k0kubun k0kubun commented Jul 15, 2025

This PR fixes the alignment of the native stack pointer on JIT-to-JIT calls for x86_64. It fixes the crash on the 30k_ifelse benchmark.

What was happening

When making a call on x86_64, SP should be 16-byte aligned. But the call instruction itself bumps it by 8 bytes, so when you're at the beginning of the function, it's misaligned. gen_entry_prologue() was pushing 32 bytes, so the JIT trampoline carried the misaligned state to the call into the JIT function.

When the call instruction makes another 8-byte bump to enter the JIT function, it's aligned, so aligned_stack_bytes() and alloc_regs() pushing 16-byte-aligned bytes made sense. However, when it makes a JIT-to-JIT call, the call instruction makes it misaligned on the callee JIT function, so C functions called in it had misaligned SP.

Moreover, when a JIT-to-JIT side-exits, the caller frame did not restore the frame size bumped for spilled basic block arguments. So leaving JIT-to-JIT calls with many basic block arguments could lead to wrong/misaligned SP as well.

What happens now

This PR changes gen_entry_prologue() to push 24 bytes instead. Combined with the 8 byte pushed by the call instruction, the JIT function is called with SP aligned properly. The JIT function then needs to fix the SP misaligned by the call instruction, so aligned_stack_bytes() now pushes an odd number of slots.

This PR also changes JIT-to-JIT calls to use a small side exit that only restores SP when the call returns Qundef.

@k0kubun k0kubun changed the title ZJIT: Fix SP alignment on JIT entry for x86_64 ZJIT: Fix SP alignment on JIT-to-JIT calls for x86_64 Jul 15, 2025
@k0kubun k0kubun marked this pull request as ready for review July 15, 2025 21:03
@matzbot matzbot requested a review from a team July 15, 2025 21:03
@k0kubun k0kubun linked an issue Jul 15, 2025 that may be closed by this pull request
Copy link
Member

@XrXr XrXr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It always seemed weird to me that it's aligned right before CALL runs, not after, since that forces the callee to align the stack if it wants it, which kind of defeats the whole point. But ay, I guess they assume everyone wants to at least push rbp in the olden days and this is some sort of carry-over.

Comment on lines -514 to -517
// On x86_64, maintain 16-byte stack alignment
if cfg!(target_arch = "x86_64") {
asm.cpush(SP);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, this looked suspect to me, so I'm glad we're fixing it.

Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
@k0kubun k0kubun merged commit af1ad78 into ruby:master Jul 16, 2025
88 of 92 checks passed
@k0kubun k0kubun deleted the zjit-align-sp branch July 16, 2025 16:50
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.

ZJIT: 30k_ifelse crashes; rsp is misaligned
4 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy