Ruby: Porting YJIT to Rust
bugs.ruby-lang.org
bugs.ruby-lang.org
Besides that, I prefer Zig to Rust, as a long-term C programmer, but all up to you." - Matz (Yukihiro Matsumoto)
https://github.com/artichoke/artichoke
It’s ruby, implemented in rust. Early days, but very interesting.
(I have no affiliation or involvement with it, just a fan)
These implemented-in-Rust bits expose themselves to the remaining C with `extern "C"` APIs written in Rust that maintain ABI compat with the mruby code they replace.
The mruby VM is getting eaten by the Rust parts, so I don't think it's quite fair to say that Artichoke uses mruby as an off the shelf component. To fully move beyond mruby though to a native Rust VM will take time.
The real problem is whether or not the expense of porting it is justified. Taking a look at the git repository of it (before it was merged into upstream), I understand why they want to rewrite it in Rust, the repository looks like a complete mess. I don't know if they want to use an existing JIT codegen like LLVM or Cranelift, or their own.
Ruby has support for plenty of "exotic" systems like HP UX, AIX etc. It's unclear how many people actually use it, but it's there.
> I don't know if they want to use an existing JIT codegen like LLVM or Cranelift, or their own.
Their own.
No idea about HP-UX, it is impossible to find anything now, apparently HPE has buried almost everything about it. Completely unrelated to how good it used to be about 20 years ago.
> you wouldn't use ruby outside of Linux, Windows, Mac, FreeBSD, OpenBSD
Isn't quite true.
My bad, that's really not what I understood from your initial statement. But yes agreed.
The only real downside is discussed on the ticket. Ruby is primarily installed from source, so requiring a second toolchain is not ideal.
The goals and constraints of practical dynlang JITs often differ a bit from those for statically typed languages. The JITs for statically typed languages are often fairly "straightforward" since the basic/primitive types are often known, and with the exception for dispatch optimizations, many large wins comes from register allocation,etc.
A dynlang JIT on the other hand far more often has unstable basic types that goes along with type guards,etc. You have a ton of optimizations in that regard that comes before it's even time to consider more than basic register allocation optimizations (See for example the recent posts on the new Erlang JIT).
In this particular case Maxime's PHd was a JS JIT that implemented something called Basic-Block-Versioning, you can see an early paper on this at https://arxiv.org/abs/1411.0352
My suspicion is that the existing codegens you mention comes with a lot of baggage that might be in the way of how a lazy codegen like they want should be structured. I wrote a small experimental lazy dynamic JIT once and the structure definitely got twisted around and "direct" access to all parts definitely was a plus.
It's refreshing to see a project explicitly call this out as a benefit for adopting Rust. Love it or hate it, the RIIR (Rewrite It In Rust) crowd certainly has a lot of momentum behind it.
It seems to be a proposal. The proposal was made by a user who was registered on 09/27/2021.
The text you quoted was included on his proposal. The project itself is not explicitly call that one out.
maximecb is the lead of YJIT project in Shopify.
(Also, the last time I checked, cranelift emitted extremely suboptimal code. That's not their fault given the design constraints (it's a new project and they're aiming to beat LLVM's SelectionDAG in codegen performance), but it's probably not ideal given Ruby's long term performance goals. I'm also not sure how easy it would be to retrofit the LBBV[1] architecture of YJIT onto cranelift.)
Unfortunately it is still way too early for Zig.
I also wonder what is happening to TruffleRuby inside Shopify. And where is TenderJIT :)
My C complaints are well known, yet I don't see the need to make the build system even more complex, dropping platform support, for the benefit of yet another language, regardless of Rust or Zig winning in the end.
Then they shouldn't have merged the JIT to start with and just do their own Ruby implementation instead.
"just"...
Several other Ruby JIT projects (Rubinius, JRuby, TruffleRuby, etc) have poured tons of resources, and while they perform very well, the adoption is still very low because keeping up with the main implementation takes tons of effort.
On the other hand YJIT managed to speedup real world codebases with pretty much 100% compatibility in under a year of development by a fairly small team.
Shopify already invest quite a lot in TruffleRuby, that's the new implementation moonshot you call for, YJIT is the more grounded, shorter term hedge.
I think you overestimate the size of the YJIT codebase. It's a very dense codebase in term on developer hours, translating it is far cheaper than it was to develop it from scratch.
It also doesn't come from out of nowhere, Alan already spent time experimenting on this idea with good results.
> is supposed to get back that money (developer hours x $ per hour) exactly how?
It's explained in the ticket, the goal is to have a better velocity once it's done.
You say you're fully aware of it but just the comment above you were advocating for something that took years to other VMs. Maybe have a little more faith in the YJIT team?
So is it worth the hassle of introducing a new language? I like the enthusiasm argument, but tbh I don't see many Rust devs become interested developing core Ruby just because a small part of it is written in Rust. My gut feeling is saying better to just keep it in C.
But anyway super excited about what the Shopify guys are doing, I want them to succeed no matter what approach they choose.
Just because it's small in term of line of code, doesn't mean it isn't tricky to maintain and extend. It's all explained on the ticket.
> Then they shouldn't have merged the JIT to start with and just do their own Ruby implementation instead.
See the thing is, building a new Ruby implementation from scratch would actually have been easier because we could have more of a clean room design. The problem is the compatibility. Making your new Ruby implementation 100% compatible with CRuby and the many Ruby gems found in the wild is extremely hard.
Well, it was great for the money we got out of it, even though it set back the client for all the issues that came out of the process until they could proceed with the same velocity as before the rewrite took place.
Hence why I usually don't see the value in rewrites of any sort, and advocate for new language adoption to always go the clean room path.
So any tier 2+ platform for Ruby now needs to wait for Rust/Zig support before considering joining the YJIT effort, maybe a compromise the Ruby team is happy with given their replies, but it does have an impact nonetheless.
It seems to have hit a minor speedbump dealing with support for Windows.
Not sure what to tell you. Things don't aways happen in the most optimal order in the real world, sometimes plans change, but I'm fairly confident that we can make this work well.
You should be using dynasm https://luajit.org/dynasm.html instead of plain C.
> Sorry, right now there is no proper documentation included other than some Examples and of course the source code. The source is well documented, though (IMHO).
and the example doesn't seem to have anything relevant to the problems identified above.
The YJIT and the CRuby are different part of the project. Just like TruffleRuby is written Ruby and based on Java GraalVM. They are basically writing a version 2 of YJIT in different language.