[HN Gopher] ZJIT is now available in Ruby 4.0
       ___________________________________________________________________
        
       ZJIT is now available in Ruby 4.0
        
       Author : ibobev
       Score  : 72 points
       Date   : 2025-12-26 17:04 UTC (5 hours ago)
        
 (HTM) web link (railsatscale.com)
 (TXT) w3m dump (railsatscale.com)
        
       | ComputerGuru wrote:
       | Non-ruby dev here. Can someone explain the side exit thing for
       | me?
       | 
       | > This meant that the code we were running had to continue to
       | have the same preconditions (expected types, no method
       | redefinitions, etc) or the JIT would safely abort. Now, we can
       | side-exit and use this feature liberally.
       | 
       | > For example, we gracefully handle the phase transition from
       | integer to string; a guard instruction fails and transfers
       | control to the interpreter.
       | 
       | > _(example showing add of two strings omitted)_
       | 
       | What is the difference between the JIT safely aborting and the
       | JIT returning control to the interpreter? Or does the JIT abort
       | mean the entire app aborts (i.e. I presumed JIT aborting means
       | continuing on the interpreter anyway?)
       | 
       | (Also, why would you _want_ the code that uses the incorrect
       | types to succeed? Isn't abort of the whole unit of execution the
       | right answer here, anyway?)
        
         | nt591 wrote:
         | Dynamic languages will allow a range of types through
         | functions. JITs add tracing and attempt to specialize the
         | functions based on the observed types at runtime. It is
         | possible that later on, the function is called with different
         | types than what the JIT observed and compiled code for. To
         | handle this, JITs will have stubs and guards. You check the
         | observed type at runtime before calling the JITted code. If the
         | type does not match, you would call a stub to generate the
         | correct machine code, or you could just call into the
         | interpreter slow path.
         | 
         | An example might be the plus operator. Many languages will
         | allow integers, floats, strings and more on either side of the
         | operator. The JIT likely will see mostly integers and optimize
         | the functions call for integer math. If later you call the plus
         | operator with two Point classes, then you would fall back to
         | the interpreter.
        
         | tekknolagi wrote:
         | In this case, we used to abort (i.e. abort(); intentionally
         | crash the entire process) but now we jump into the interpreter
         | to handle the dynamic behavior.
         | 
         | If someone writes dynamic ruby code to add two objects, it
         | should succeed in both integer and string cases. The JIT just
         | wants to optimize whatever the common case is.
        
           | ComputerGuru wrote:
           | I guess I'm confused why an actual add instruction is emitted
           | rather than whatever overloaded operation takes place when
           | the + symbol (or overloaded add vtable entry) is called (like
           | it would in other OOP languages).
        
             | tekknolagi wrote:
             | If all you're doing is summing small integers---frequently
             | the case---it's much preferable to optimize that to be fast
             | and then skip the very dynamic method lookup (the slower,
             | less common case)
        
             | zingar wrote:
             | Presumably other languages with JIT do exactly the same
             | thing?
        
           | zingar wrote:
           | I'm assuming that when you talk about crashing processes as
           | the status quo you're referring to earlier versions of zjit
           | rather than current Ruby on yjit? Because I've never seen a
           | Ruby process crash because + was called with different
           | arguments.
        
       | endorphine wrote:
       | It would be useful to explain why ZJIT exists given that there's
       | already YJIT.
       | 
       | Also, what's the long-term plan for YJIT.
        
         | fourseventy wrote:
         | I just upgraded my prod apps to run on YJIT so I'm annoyed at
         | this announcement. Feels like javascript-esque runtime churn
        
           | tekknolagi wrote:
           | Earnestly: why are you annoyed? I tried to make it clear that
           | you don't have to make any changes. If you want, you can try
           | ZJIT (which should not be anything other than a one character
           | change), but you don't have to.
        
             | fourseventy wrote:
             | Because now YJIT is deprecated and at some point in a year
             | or two I will have to have my team go through and switch
             | everything from YJIT to ZJIT. So it's creating random tech
             | debt busywork that will suck up dev resources that could
             | better be used building features.
             | 
             | In isolation, having to switch from YJIT to ZJIT isn't that
             | bad, but this same type of churn happens across so much of
             | the frameworks and technologies that my company uses that
             | in aggregate it becomes quite an annoyance.
        
               | tekknolagi wrote:
               | YJIT is _not_ deprecated. That word has a specific
               | meaning in Ruby. You can continue to use YJIT.
               | 
               | With any luck, this performance in the next year or two
               | will be enough to make it a happy change. "Damn, free
               | money" etc
        
               | pjmlp wrote:
               | Most JIT compiled languages have multiple implications,
               | each pushing each other forward.
        
         | riffraff wrote:
         | ZJIT exists because it's a more traditional design and there's
         | hope more people will have a easier time contributing[0]. Given
         | that, it seems YJIT will become unnecessary if ZJIT succeeds.
         | 
         | 0: https://railsatscale.com/2025-05-14-merge-zjit/
        
         | baggy_trough wrote:
         | The explanation is in the second paragraph of the article.
        
       | awestroke wrote:
       | I recently rewrote one of my rails apps in rust. Used Claude 4.5
       | Opus heavily and it was very fast.
       | 
       | One thing that's struck me with the new code is that's its so
       | easy to follow compared to rails. It's like two different
       | extremes on the implicit-explicit spectrum. Yet it's not like I
       | have tons more boilerplate code now, I think I have maybe 10 or
       | 20% more SLOC than before.
       | 
       | I'll probably do this with my other rails apps as well.
        
         | losteric wrote:
         | Was your app converted to use some Rust framework, or just
         | Rust?
        
           | awestroke wrote:
           | I use Axum+SQLx and for html templates I use Maud. The plan
           | is to move to Dioxus as a step 2
        
         | hu3 wrote:
         | Any language with a half decent typing system would have
         | improved the easiness to follow code around. C#, Go, PHP,
         | TypeScript, etc.
         | 
         | Ruby/Rails is awesome but it's a bit too magical sometimes and,
         | lacking types by default, doesn't help either.
        
         | azuanrb wrote:
         | You're comparing a language with a framework. Better comparison
         | would be Rust (with your choices of libraries) vs Ruby (with
         | your choices of libraries).
         | 
         | If you want to compare with Rails, you need to compare with
         | battery included Rust frameworks with equivalent batteries and
         | convention.
        
           | awestroke wrote:
           | I literally rewrote the whole app, so I think I have a pretty
           | great basis for comparison
        
       | aapoalas wrote:
       | I'm a little sad to see YJIT go down in favour of a traditional
       | design. (Yes, YJIT isn't "deprecated" but the people working on
       | it are now mainly working on something else. That's hardly a
       | great place to be in.)
       | 
       | I'm personally quite interested in trying out an LBBV JIT for
       | JavaScript, following in Chevalier-Boisvert's Higgs engine's
       | footsteps. The note about a traditional method JIT giving more
       | code for the compiler to work with does ring very true, but I'd
       | just like to see more variety in the compiler and JIT world.
       | 
       | Like: perhaps it would be possible to conjoin (say) an LBBV with
       | a SoN compiler such that LBBV takes care of the quick, basic
       | compilation and leaves behind enough data such that a SoN
       | compiler can be put to use on the whole-method result once the
       | whole method has been deemed hot enough? This is perhaps a
       | totally ridiculous idea, but it's the kind of idea that will
       | never get explored in a world with only traditional method JITs.
        
         | tekknolagi wrote:
         | In that scenario, what would you hope to get out of the LBBV?
        
           | aapoalas wrote:
           | Preface: I am not a compiler engineer at all, so I'm just
           | spitballing silliness here.
           | 
           | Avoidance of type feedback counters and such. Get LBBV to
           | clean out the redundant type checks (Higgs proved this well,
           | avoiding something like >90% of them) and produce a format,
           | perhaps a high-level bytecode or just an HIR, that can be
           | used as an input to start a method-level JIT compilation.
           | 
           | So, LBBV gives the quick and easy basic block compilation and
           | cleans up the very easy stuff but leaves enough information
           | so that a follow-up compiler can still use it as input.
        
       ___________________________________________________________________
       (page generated 2025-12-26 23:01 UTC)