| Age | Commit message (Collapse) | Author |
|
|
|
Replace `rb_yarv_class_of` call with:
- a constant check for special constants (nil, fixnums, symbols, etc)
- a check for false
- direct memory read at offset 8 for regular heap objects for the class check
|
|
ZJIT: Remove GC offsts overwritten by invalidation
|
|
ZJIT: Set PC before StringCopy
This function allocates.
|
|
* ZJIT: Implement SingleRactorMode invalidation
* ZJIT: Add macro for compiling jumps
* ZJIT: Fix typo in comment
* YJIT: Fix typo in comment
* ZJIT: Avoid using unexported types in zjit.h
`enum ruby_vminsn_type` is declared in `insns.inc` and is not exported.
Using it in `zjit.h` would cause build errors when the file including it
doesn't include `insns.inc`.
|
|
|
|
This allows us to annotate builtin functions with their return type.
|
|
|
|
|
|
|
|
|
|
Untangle the logic a bit and specifically:
* catch `gen_entry` failures
* don't set `start_ptr` until all recursive calls succeed
Co-authored-by: Alan Wu <alanwu@ruby-lang.org>
|
|
Add support for `--zjit-allowed-iseqs=SomeFile` and
`--zjit-log-compiled-iseqs=SomeFile` so we can restrict and inspect
which ISEQs get compiled.
Then add `jit_bisect.rb` which we can run to try and narrow a failing
script. For example:
plum% ../tool/zjit_bisect.rb ../build-dev/miniruby "test.rb"
I, [2025-07-29T12:41:18.657177 #96899] INFO -- : Starting with JIT list of 4 items.
I, [2025-07-29T12:41:18.657229 #96899] INFO -- : Verifying items
I, [2025-07-29T12:41:18.726213 #96899] INFO -- : step fixed[0] and items[4]
I, [2025-07-29T12:41:18.726246 #96899] INFO -- : 4 candidates
I, [2025-07-29T12:41:18.797212 #96899] INFO -- : 2 candidates
Reduced JIT list:
bar@test.rb:8
plum%
We start with 4 compiled functions and shrink to just one.
|
|
|
|
|
|
|
|
This implements similar fast-path guard type checks as YJIT.
|
|
Previously, ZJIT miscompiled the following because of native SP
interference.
def a(n1,n2,n3,n4,n5,n6,n7,n8) = [n8]
a(0,0,0,0,0,0,0, :ok)
Commented problematic disassembly:
; call rb_ary_new_capa
mov x0, #1
mov x16, #0x1278
movk x16, #0x4bc, lsl #16
movk x16, #1, lsl #32
blr x16
; call rb_ary_push
mov x1, x0
str x1, [sp, #-0x10]! ; c_push() from alloc_regs()
mov x0, x1 ; arg0, the array
ldur x1, [sp] ; meant to be arg1=n8, but sp just moved!
mov x16, #0x3968
movk x16, #0x4bc, lsl #16
movk x16, #1, lsl #32
blr x16
Since the frame pointer stays constant in the body of the function,
static offsets based on it don't run the risk of being invalidated by SP
movements.
Pass the registers to preserve through Insn::FrameSetup. This allows ARM
to use STP and waste no gaps between EC, SP, and CFP.
x86 now preserves and restores RBP since we use it as the frame pointer.
Since all arches now have a frame pointer, remove offset based SP
movement in the epilogue and restore registers using the frame pointer.
|
|
Previously, for 8+ params we wound up clobbering the self param when
putting the last param in memory in the JIT entry point:
# ZJIT entry point: a@../test.rb:5
<snip>
ldur x0, [x19, #0x18]
# set method params: 8
ldur x1, [x21, #-0x58]
ldur x2, [x21, #-0x50]
ldur x3, [x21, #-0x48]
ldur x4, [x21, #-0x40]
ldur x5, [x21, #-0x38]
ldur x11, [x21, #-0x30]
ldur x12, [x21, #-0x28]
ldur x0, [x21, #-0x20]
stur x0, [sp, #-0x20]
bl #0x11e17018c
Doing the memcpys for parameters in memory first avoids this clobbering.
# set method params: 8
ldur x0, [x21, #-0x20]
stur x0, [sp, #-0x20]
ldur x12, [x21, #-0x28]
ldur x11, [x21, #-0x30]
ldur x5, [x21, #-0x38]
ldur x4, [x21, #-0x40]
ldur x3, [x21, #-0x48]
ldur x2, [x21, #-0x50]
ldur x1, [x21, #-0x58]
ldur x0, [x19, #0x18]
|
|
We weren't firing write barriers before when writing to imemo/env
objects. Wbcheck caught this with test/ruby/test_refinement.rb:
ruby -v: ruby 3.5.0dev (2025-07-22T17:05:58Z wbcheck 2569a80954) +ZJIT dev +PRISM +GC[wbcheck] [x86_64-linux]
WBCHECK ERROR: Missed write barrier detected!
Parent object: 0x558de9f4e6e0 (wb_protected: true)
rb_obj_info_dump: 0x0000558de9f4e6e0 T_IMEMO/<env>
Reference counts - snapshot: 3, writebarrier: 0, current: 4, missed: 1
Missing reference to: 0x558decf37c30
rb_obj_info_dump: 0x0000558decf37c30 method/UnboundMethod method
WBCHECK SUMMARY: Found 1 objects with missed write barriers (1 total violations)
|
|
Or else the following returns garbage since it loads after
moving SP. Prior bad disassembly:
def a(n1,n2,n3,n4,n5,n6,n7,n8) = n8
a(1,1,1,1,1,1,1,0)
# Block: bb0(v0, v1, v2, v3, v4, v5, v6, v7, v8)
stp x29, x30, [sp, #-0x10]!
mov x29, sp
# bump C stack pointer
sub sp, sp, #0x10
# Insn: v10 Return v8
# pop stack frame
adds x19, x19, #0x38
stur x19, [x20, #0x10]
# restore C stack pointer
add sp, sp, #0x10
mov sp, x29
ldp x29, x30, [sp], #0x10
ldur x0, [sp]
ret
|
|
ZJIT: Support invalidating method redefinition
This commit adds support for the MethodRedefined invariant to be invalidated
when a method is redefined.
Changes:
- Added CME pointer to the MethodRedefined invariant in HIR
- Updated all places where MethodRedefined invariants are created to
include the CME pointer
- Added handling for MethodRedefined invariants in gen_patch_point to
call track_cme_assumption, which registers the patch point for
invalidation when rb_zjit_cme_invalidate is called
This ensures that when a method is redefined, all JIT code that
depends on that method will be properly invalidated.
|
|
This lets us ZJIT compiled functions show up in the profiles of, say,
perf, or samply.
Fix https://github.com/Shopify/ruby/issues/634
|
|
|
|
This issues writebarriers for objects added via gc_offsets or by
profiling. This may be slower than writebarrier_remember, but we would
like it to be more debuggable.
Co-authored-by: Max Bernstein <ruby@bernsteinbear.com>
Co-authored-by: Stan Lo <stan001212@gmail.com>
|
|
|
|
|
|
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
|
|
|
|
|
|
Previously, gen_param() access slots at `SP-x` for `x≥0` after subtracting from
SP, so it was accessing slots from above the top of the stack. Also, the
slots gen_entry_params() wrote to at entry point did not correspond to
the slots access inside the JIT function.
Redo the stack frame layout so that inside the function slots are at
`SP+x`. Write to those slots in the entry point by anticipating the size
of the frame.
Fixes test_spilled_method_args().
|
|
Now that params can be in memory, this particular load_into() was
panicking with "Invalid operands for LDUR" with
test_spilled_method_args() on ARM.
Since it's documented to be for register destinations let's validate it.
|
|
|
|
This DRYs up the `asm_comment!` + `asm.ccall` combo, and makes ccalls
have a comment by default.
|
|
Co-authored-by: Alan Wu <alansi.xingwu@shopify.com>
Co-authored-by: Stan Lo <stan.lo@shopify.com>
|
|
|
|
* ZJIT: Improve asm comments for side exits
* Use GuardType(Type) and GuardBitEquals(VALUE)
|
|
Co-authored-by: Max Bernstein <max@bernsteinbear.com>
|
|
* ZJIT: Avoid optimizing locals on eval
* Maintain the local state for eval
|
|
|
|
|
|
ZJIT already can generate guard type instructions for *Exact types.
For example:
```
def test(strings)
strings.map do |string|
string.bytesize
end
end
test(["foo", "bar"])
```
```
HIR:
fn block in test:
bb0(v0:BasicObject, v1:BasicObject):
PatchPoint MethodRedefined(String@0x1014be890, bytesize@0x19f1)
v7:StringExact = GuardType v1, StringExact
v8:Fixnum = CCall bytesize@0x16fa4cc18, v7
Return v8
```
But zjit only supported guarding fixnums so this script would panic.
This commit adds support for guarding *Exact types.
|
|
Along the same lines as the `opnd` macro we already have, but for a
`Vec<InsnId>` instead of a single `InsnId`.
This gets a few for loops and `jit.get_opnd` calls out of the `gen_`
functions.
|
|
This PR adds a simple validator for ZJIT's HIR.
See issue https://github.com/Shopify/ruby/issues/591
|
|
|
|
|
|
This makes it clearer what is unimplemented when looking at HIR dumps.
|
|
Co-authored-by: Max Bernstein <max@bernsteinbear.com>
|
|
* ZJIT: Stop tracking EP == BP assumption on JIT entry
* Enable test_method.rb as well
|
|
|