Skip to content

ZJIT: Implement concatstrings #13789

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Conversation

XrXr
Copy link
Member

@XrXr XrXr commented Jul 4, 2025

  • ZJIT: DRY up underscore rexport anti-pattern
  • ZJIT: Implement concatstrings

Quite tricky to use the native stack to pass a C VALUE[].

@matzbot matzbot requested a review from a team July 4, 2025 16:03
@XrXr XrXr force-pushed the zjit-concatstrings branch from 2f8723d to 33bc33d Compare July 4, 2025 17:08
// Save PC since the call allocates and can raise
gen_save_pc(asm, state);

// We've moved the SP, so the array is at SP or one element above
Copy link
Contributor

@composerinteralia composerinteralia Jul 5, 2025

Choose a reason for hiding this comment

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

I was working on a branch for toregexp, which looks quite similar to this: https://github.com/ruby/ruby/compare/master...composerinteralia:ruby:zjit-toregexp?expand=1

I managed to avoid this conditional for where the array is located by growing the stack first, then putting the strings onto the stack relative to the new SP. That way the extra space for alignment ends up after the array instead of before it. Edit: Oops, ignore that. I had missed your comment about writing before moving SP since the source might be from the stack.

I was also playing around with a cpush_vec, since I knew we'd need something like this for concatstring as well (and maybe some others). Not sure about it yet though.

(Sharing just in case it's helpful—I'll plan to update my toregexp branch before opening a PR to match whatever you do here).

let dest = Opnd::mem(64, NATIVE_STACK_PTR, i32::try_from(strings.len() - i).ok()? * -SIZEOF_VALUE_I32);
asm.mov(dest, jit.get_opnd(*string)?);
}
// Write, then move the SP, since the source might be from the stack
Copy link
Member Author

Choose a reason for hiding this comment

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

@k0kubun Actually, are all changes to SP unsafe because the backend will auto spill stuff around ccall based on a fixed offset from native SP? In other words, do we have to inform the backend about any changes to native SP if it does auto spill?

Copy link
Member

Choose a reason for hiding this comment

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

are all changes to SP unsafe because the backend will auto spill stuff around ccall based on a fixed offset from native SP?

Are you saying giving (native) SP-based memory operands to ccall is unsafe because ccall may also bump the native SP to spill live registers before moving these memory operands into C argument registers? Is my understanding correct?

do we have to inform the backend about any changes to native SP if it does auto spill?

I guess we could maintain c_sp_offset (or native_sp_offset) in Assembler and let the split pass adjust all memory operands based on native SP in its operand iterator loop. It might solve #13802 (comment) as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

Are you saying giving (native) SP-based memory operands to ccall is unsafe because ccall may also bump the native SP to spill live registers before moving these memory operands into C argument registers? Is my understanding correct?

Yeah, sounds like a possible failure mode. I see that spilling is not implemented for now 1. I was picturing a fixed-size frame for all auto generated spills, where there is a pre-determined offset for each VReg at each spill site. It would just write to say, [SP, -0x20] for some VReg. If we change SP from underneath that code, it would clobber. Also, in case a spilled VReg is passed as an argument and it auto-reloads it to a register, SP being different would have it read the wrong value.

I guess we could maintain c_sp_offset (or native_sp_offset) in Assembler and let the split pass adjust all memory operands based on native SP in its operand iterator loop. It might solve #13802 (comment) as well.

Something like that should work. These references are based on the native frame pointer, conventionally rbp on x86, and because we don't keep a base pointer explicitly and SP can change, there is a moving offset to get the frame base from SP.

Footnotes

  1. Or is this line outdated? debug!("spilling VReg is not implemented yet, can't evacuate C_RET_REG on CCall");

Copy link
Member

Choose a reason for hiding this comment

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

Or is this line outdated?

We bail out on that now, so it doesn't panic anymore but it's still not implemented yet.

XrXr added 2 commits July 15, 2025 16:27
Keeping the same name makes re-exporting more concise.
Quite tricky to use the native stack to pass a C `VALUE[]`.
@XrXr XrXr force-pushed the zjit-concatstrings branch from 33bc33d to 9b7432c Compare July 15, 2025 21:15
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.

3 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