Feature #19420
closedSimplify MJIT implementation
Description
Background¶
Implementation complexity¶
Because MJIT needs to run a C compiler and be able to call almost everything in vm.c, it has brought MJIT-specific complexity to the Ruby VM implementation:
- GVL and waitpid hacks for
Process.waitall
- @ko1 (Koichi Sasada) and @ioquatix (Samuel Williams) have had problems dealing with it.
-
vm_base_ptr
dependency from MJIT- @ko1 (Koichi Sasada) wanted to remove
cfp->__bp__
8dd0fb9039bbe6152ea5542e6bc70de152871e23 - This is technically not the fault of the MJIT design, but the current implementation relies on it.
- @ko1 (Koichi Sasada) wanted to remove
- MJIT header and
MJIT_HEADER
macro- It seems like some build dependency is missing for it and my local build with
-j
randomly fails on MJIT header build.
- It seems like some build dependency is missing for it and my local build with
- MJIT-specific frame handling
-
catch_except_p
flag in ISeq -
jit_enable_p
flag invm_exec
-
leaf
attribute in insns
-
-
MJIT_FUNC_EXPORTED
functions
Third-party JIT experiments¶
Despite YJIT being the only non-experimental JIT compiler in CRuby from Ruby 3.2, people still experiment with other JIT implementations, e.g. vnmakarov/ruby (sir-mirjit), tenderlove/tenderjit, jhawthorn/hawthjit, which I think is a good thing for the future of Ruby, and for YJIT as well.
In Ruby 3.2, MJIT was rewritten in Ruby. It also meant that you could replace CRuby's JIT implementation by monkey-patching MJIT, which became the first ever "third-party JIT backdoor". I know two people started using it for that purpose. I want people (including myself through MJIT) to keep experimenting with Ruby performance, so I don't want to just get rid of this. RubyVM::MJIT::C
and RubyVM::MJIT::Hooks
are something that third-party gems can't easily provide. They should be considered as something similar to JVMCI (Java's JIT interface) whether we make them private or not.
Proposal¶
- Change MJIT to a simple JIT implementation that doesn't rely on a C compiler at runtime, which works like YJIT (to remove all the complexity mentioned above) but is written in Ruby (to keep offerring modules for third-party JITs).
- I have a PoC branch, which needs rebase and cleanup but passes
make check
. It currently supports very limited operations and is not really useful, but I intend to keep improving this outside my work hours (that I dedicate to YJIT), sometimes experimenting with things that are not done in YJIT. Note that we could still solve the above problems even with the current patch. - It shouldn't increase the maintenance cost of CRuby too much.
- You're free to just mark something "can't compile" in MJIT when VM is changed.
- It should also not support platforms that YJIT doesn't support. When it's upstreamed for the first time, I intend to make it like Ruby 3.1 YJIT, i.e. supporting only x86_64 Linux and BSD.
- It's also kind of useful in the sense that it requires neither a C compiler at runtime nor a Rust compiler at build time.
- I'm thinking about renaming it to "RJIT" ("R"uby "JIT") since it's no longer a "M"ethod "JIT" anymore.
- Note that part of the implementation cannot be implemented as a gem.
RubyVM::MJIT::C
(that usesPrimitive
) andRubyVM::MJIT::Hooks
(that are hooked from VM internals) must be part of the interpreter. I'm open to making other parts a gem if other people want me to, but it might come with a maintainability trade-off because of that interpreter dependency.
- I have a PoC branch, which needs rebase and cleanup but passes
Updated by k0kubun (Takashi Kokubun) almost 2 years ago
- Description updated (diff)
Updated by k0kubun (Takashi Kokubun) almost 2 years ago
- Description updated (diff)
Updated by k0kubun (Takashi Kokubun) almost 2 years ago
- Description updated (diff)
Updated by ioquatix (Samuel Williams) almost 2 years ago
I'm very happy about this, it sounds like a good path forward.
Updated by k0kubun (Takashi Kokubun) almost 2 years ago
- Description updated (diff)
Updated by k0kubun (Takashi Kokubun) almost 2 years ago
- Description updated (diff)
Updated by k0kubun (Takashi Kokubun) almost 2 years ago
- Description updated (diff)
Updated by k0kubun (Takashi Kokubun) almost 2 years ago
- Description updated (diff)
Updated by k0kubun (Takashi Kokubun) almost 2 years ago
- Description updated (diff)
Updated by k0kubun (Takashi Kokubun) almost 2 years ago
- Description updated (diff)
Updated by k0kubun (Takashi Kokubun) almost 2 years ago
- Description updated (diff)
Updated by rubyFeedback (robert heiler) almost 2 years ago
This could also, if I understood it correctly, help "one-man ruby implementations"
such as natalie by Tim. (I don't know the current status of JIT support in natalie
in natalie though. But it's nice to see that a single person could, at the least
in theory, implement a working ruby implementation even in 2023 and beyond.)
Updated by k0kubun (Takashi Kokubun) almost 2 years ago
- Description updated (diff)
Updated by k0kubun (Takashi Kokubun) almost 2 years ago
- Status changed from Open to Closed
Applied in changeset git|22d944c8b76be04dc437100c46626db5fe9dd7f0.
Avoid crashing at a random ISEQ access
[Feature #19420]