4 Commits
Author SHA1 Message Date
Nozomi Hijikata 81c5830a66 ZJIT: Inline BasicObject#!= through a JIT hook (#19162)
Closes: https://github.com/Shopify/ruby/issues/884

Inline `BasicObject#!=` by using a ZJIT hook. This expands specialization coverage to additional cases beyond the existing String and Integer specializations.

Although this might add some overhead in the interpreter when ZJIT is enabled, as the `opt_neq` fast path requires the C definition, the benchmarks below show speedups in several cases (e.g. lobsters, railsbench). I ran the benchmarks several times. The speedups varied between runs, but I consistently observed improvements over the previous implementation.

```
zjit-master: ruby 4.1.0dev (2026-10-10T08:21:06Z master 05917fd1e6) +ZJIT stats +PRISM [arm64-darwin25]
zjit-basicobject-hook: ruby 4.1.0dev (2026-10-10T13:30:56Z zjit-basicobject-n.. a6f95cadaa) +ZJIT stats +PRISM [arm64-darwin25]
ruby-bench: 3cc371202311fe2c821a6adb5adfced364f029de

-------------  ----------------  --------------------------  -----------------------------  ---------------------------------
bench          zjit-master (ms)  zjit-basicobject-hook (ms)  zjit-basicobject-hook 1st itr  zjit-master/zjit-basicobject-hook
liquid-render      44.6 ± 10.2%                 43.9 ± 6.3%                          0.933                              1.014
lobsters           415.1 ± 6.7%                384.1 ± 4.7%                          1.070                              1.081
railsbench         592.1 ± 5.8%                545.8 ± 2.0%                          1.117                              1.085
-------------  ----------------  --------------------------  -----------------------------  ---------------------------------
```
---

<details>
<summary>Resolved: specialization with statically known receiver types</summary>

Note: Currently, the `==` call inside `BasicObject#!=` uses a profile shared across callers. When that profile is polymorphic, `==` can fall back to a dynamic send even when the receiver's exact type is known in the caller.
As a follow-up, we could improve specialization of `==` inside the inlined `!=` by using receiver types known at the call site, even when the shared profile for `==` is polymorphic.

```rb
2.times do
  "x" != nil
  1 != nil
end

NULL = Object.new
def test(value) = NULL != value

4.times { test(nil) }
```
```sh
#  ./miniruby --zjit-dump-hir --zjit-call-threshold=4 --zjit-num-profiles=4 ../test.rb
```
On master:
```
v30:ObjectExact[VALUE(...)] = Const Value(VALUE(...))
PatchPoint MethodRedefined(Object@..., !=@..., cme:...)
PatchPoint MethodRedefined(Object@..., ==@..., cme:...)
v51:CBool = IsBitNotEqual v30, v11
v52:BoolExact = BoxBool v51
```

On current branch:
```
v30:ObjectExact[VALUE(...)] = Const Value(VALUE(...))
PatchPoint NoSingletonClass(Object@...)
PatchPoint MethodRedefined(Object@..., !=@..., cme:...)
PushInlineFrame :!=, v30 (...), num_args=1
v68:BasicObject = Send v30, :==, v11 # SendFallbackReason: Send: polymorphic fallback
v71:CBool = Test v68
CondBranch v71, bb14(), bb8()

// Removing the initial 2.times block lets the current branch specialize the comparison to IsBitEqual.
```

</details>
2026-10-14 18:00:32 +00:00
Max Bernstein 98e6f5e4bc Enable ZJIT jit hooks for with_jit builtins 2026-02-09 19:28:04 -05:00
Godfrey Chan f84bbb4238 ZJIT: add support for lazy RubyVM::ZJIT.enable
This implements Shopify#854:

- Splits boot-time and enable-time initialization,
  tracks progress with `InitializationState` enum

- Introduces `RubyVM::ZJIT.enable` Ruby method for
  enabling the JIT lazily, if not already enabled

- Introduces `--zjit-disable` flag, which can be
  used alongside the other `--zjit-*` flags but
  prevents enabling the JIT at boot time

- Adds ZJIT infra to support JIT hooks, but this
  is not currently exercised (Shopify/ruby#667)

Left for future enhancements:

- Support kwargs for overriding the CLI flags in
  `RubyVM::ZJIT.enable`

Closes Shopify#854
2025-11-18 08:35:09 -08:00
Takashi Kokubun 2cd10de330 ZJIT: Prepare for sharing JIT hooks with ZJIT (#14044) 2025-07-30 10:11:10 -07:00